diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ConvFit.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ConvFit.h index 0a8f60acd03db66326f56aca299f2751036ba161..98a4fcfe756138808270ea99b2d1c7200a8a2667 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ConvFit.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ConvFit.h @@ -6,72 +6,73 @@ #include "MantidAPI/MatrixWorkspace_fwd.h" #include "MantidAPI/CompositeFunction.h" -namespace MantidQt -{ -namespace CustomInterfaces -{ -namespace IDA -{ - class DLLExport ConvFit : public IndirectDataAnalysisTab - { - Q_OBJECT +namespace MantidQt { +namespace CustomInterfaces { +namespace IDA { +class DLLExport ConvFit : public IndirectDataAnalysisTab { + Q_OBJECT - public: - ConvFit(QWidget * parent = 0); +public: + ConvFit(QWidget *parent = 0); - private: - virtual void setup(); - virtual void run(); - virtual bool validate(); - virtual void loadSettings(const QSettings & settings); +private: + virtual void setup(); + virtual void run(); + virtual bool validate(); + virtual void loadSettings(const QSettings &settings); - private slots: - void typeSelection(int index); - void bgTypeSelection(int index); - void newDataLoaded(const QString wsName); - void extendResolutionWorkspace(); - void updatePlot(); - void plotGuess(); - void singleFit(); - void specMinChanged(int value); - void specMaxChanged(int value); - void minChanged(double); - void maxChanged(double); - void backgLevel(double); - void updateRS(QtProperty*, double); - void checkBoxUpdate(QtProperty*, bool); - void hwhmChanged(double); - void hwhmUpdateRS(double); - void fitContextMenu(const QPoint &); - void fixItem(); - void unFixItem(); - void showTieCheckbox(QString); - void updatePlotOptions(); - void singleFitComplete(bool error); +private slots: + void typeSelection(int index); + void bgTypeSelection(int index); + void newDataLoaded(const QString wsName); + void extendResolutionWorkspace(); + void updatePlot(); + void plotGuess(); + void singleFit(); + void specMinChanged(int value); + void specMaxChanged(int value); + void minChanged(double); + void maxChanged(double); + void backgLevel(double); + void updateRS(QtProperty *, double); + void checkBoxUpdate(QtProperty *, bool); + void hwhmChanged(double); + void hwhmUpdateRS(double); + void fitContextMenu(const QPoint &); + void fixItem(); + void unFixItem(); + void showTieCheckbox(QString); + void singleFitComplete(bool error); + void fitFunctionSelected(const QString &); - private: - boost::shared_ptr<Mantid::API::CompositeFunction> createFunction(bool tieCentres=false); - double getInstrumentResolution(std::string workspaceName); - QtProperty* createLorentzian(const QString &); - QtProperty* createDiffSphere(const QString &); - QtProperty* createDiffRotDiscreteCircle(const QString &); - void createTemperatureCorrection(Mantid::API::CompositeFunction_sptr product); - void populateFunction(Mantid::API::IFunction_sptr func, Mantid::API::IFunction_sptr comp, QtProperty* group, const std::string & pref, bool tie); - QString fitTypeString() const; - QString backgroundString() const; - QString minimizerString(QString outputName) const; - Ui::ConvFit m_uiForm; - QtStringPropertyManager* m_stringManager; - QtTreePropertyBrowser* m_cfTree; - QMap<QtProperty*, QtProperty*> m_fixedProps; - Mantid::API::MatrixWorkspace_sptr m_cfInputWS; - QString m_cfInputWSName; - bool m_confitResFileType; - Mantid::API::IAlgorithm_sptr m_singleFitAlg; - QString m_singleFitOutputName; +private: + boost::shared_ptr<Mantid::API::CompositeFunction> + createFunction(bool tieCentres = false); + double getInstrumentResolution(std::string workspaceName); + QtProperty *createFitType(const QString &); - }; + void createTemperatureCorrection(Mantid::API::CompositeFunction_sptr product); + void populateFunction(Mantid::API::IFunction_sptr func, + Mantid::API::IFunction_sptr comp, QtProperty *group, + const std::string &pref, bool tie); + QString fitTypeString() const; + QString backgroundString() const; + QString minimizerString(QString outputName) const; + QStringList getFunctionParameters(QString); + void updatePlotOptions(); + + Ui::ConvFit m_uiForm; + QtStringPropertyManager *m_stringManager; + QtTreePropertyBrowser *m_cfTree; + QMap<QtProperty *, QtProperty *> m_fixedProps; + Mantid::API::MatrixWorkspace_sptr m_cfInputWS; + QString m_cfInputWSName; + bool m_confitResFileType; + Mantid::API::IAlgorithm_sptr m_singleFitAlg; + QString m_singleFitOutputName; + QStringList m_fitStrings; +}; } // namespace IDA } // namespace CustomInterfaces } // namespace MantidQt diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ConvFit.ui b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ConvFit.ui index fb172a6595d5dcf7a05d396c2f15dfdb2d733c99..c997de2f86eacfb29fd7b8ade6e586b162fb79a6 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ConvFit.ui +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/ConvFit.ui @@ -143,14 +143,29 @@ </item> <item> <property name="text"> - <string>Diffusion Sphere</string> + <string>InelasticDiffSphere</string> </property> </item> <item> <property name="text"> - <string>Diffusion Circle</string> + <string>InelasticDiffRotDiscreteCircle</string> </property> </item> + <item> + <property name="text"> + <string>ElasticDiffSphere</string> + </property> + </item> + <item> + <property name="text"> + <string>ElasticDiffRotDiscreteCircle</string> + </property> + </item> + <item> + <property name="text"> + <string>StretchedExpFT</string> + </property> + </item> </widget> </item> </layout> diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/ConvFit.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/ConvFit.cpp index 4d64f9a09be1b757859df468806500a9475d9e6a..0c08f51ba496c2b6f68089b501c2ac0e6802a0fa 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/ConvFit.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/ConvFit.cpp @@ -1,11 +1,12 @@ #include "MantidQtCustomInterfaces/Indirect/ConvFit.h" #include "MantidQtCustomInterfaces/UserInputValidator.h" + #include "MantidQtMantidWidgets/RangeSelector.h" #include "MantidAPI/AlgorithmManager.h" -#include "MantidAPI/FunctionFactory.h" #include "MantidAPI/FunctionDomain1D.h" +#include "MantidAPI/FunctionFactory.h" #include <QDoubleValidator> #include <QFileInfo> @@ -16,1459 +17,1478 @@ using namespace Mantid::API; -namespace -{ - Mantid::Kernel::Logger g_log("ConvFit"); +namespace { +Mantid::Kernel::Logger g_log("ConvFit"); } -namespace MantidQt -{ -namespace CustomInterfaces -{ -namespace IDA -{ - ConvFit::ConvFit(QWidget * parent) : - IndirectDataAnalysisTab(parent), - m_stringManager(NULL), m_cfTree(NULL), - m_fixedProps(), - m_cfInputWS(), m_cfInputWSName(), - m_confitResFileType() - { - m_uiForm.setupUi(parent); - } +namespace MantidQt { +namespace CustomInterfaces { +namespace IDA { +ConvFit::ConvFit(QWidget *parent) + : IndirectDataAnalysisTab(parent), m_stringManager(NULL), m_cfTree(NULL), + m_fixedProps(), m_cfInputWS(), m_cfInputWSName(), m_confitResFileType() { + m_uiForm.setupUi(parent); +} - void ConvFit::setup() - { - // Create Property Managers - m_stringManager = new QtStringPropertyManager(); - - // Create TreeProperty Widget - m_cfTree = new QtTreePropertyBrowser(); - m_uiForm.properties->addWidget(m_cfTree); - - // add factories to managers - m_cfTree->setFactoryForManager(m_blnManager, m_blnEdFac); - m_cfTree->setFactoryForManager(m_dblManager, m_dblEdFac); - - // Create Range Selectors - auto fitRangeSelector = m_uiForm.ppPlot->addRangeSelector("ConvFitRange"); - auto backRangeSelector = m_uiForm.ppPlot->addRangeSelector("ConvFitBackRange", - MantidWidgets::RangeSelector::YSINGLE); - auto hwhmRangeSelector = m_uiForm.ppPlot->addRangeSelector("ConvFitHWHM"); - backRangeSelector->setColour(Qt::darkGreen); - backRangeSelector->setRange(0.0, 1.0); - hwhmRangeSelector->setColour(Qt::red); - - // Populate Property Widget - - // Option to convolve members - m_properties["Convolve"] = m_blnManager->addProperty("Convolve"); - m_cfTree->addProperty(m_properties["Convolve"]); - m_blnManager->setValue(m_properties["Convolve"], true); - - // Max iterations option - m_properties["MaxIterations"] = m_dblManager->addProperty("Max Iterations"); - m_dblManager->setDecimals(m_properties["MaxIterations"], 0); - m_dblManager->setValue(m_properties["MaxIterations"], 500); - m_cfTree->addProperty(m_properties["MaxIterations"]); - - // Fitting range - m_properties["FitRange"] = m_grpManager->addProperty("Fitting Range"); - m_properties["StartX"] = m_dblManager->addProperty("StartX"); - m_dblManager->setDecimals(m_properties["StartX"], NUM_DECIMALS); - m_properties["EndX"] = m_dblManager->addProperty("EndX"); - m_dblManager->setDecimals(m_properties["EndX"], NUM_DECIMALS); - m_properties["FitRange"]->addSubProperty(m_properties["StartX"]); - m_properties["FitRange"]->addSubProperty(m_properties["EndX"]); - m_cfTree->addProperty(m_properties["FitRange"]); - - // FABADA - m_properties["FABADA"] = m_grpManager->addProperty("Bayesian"); - m_properties["UseFABADA"] = m_blnManager->addProperty("Use FABADA"); - m_properties["FABADA"]->addSubProperty(m_properties["UseFABADA"]); - m_properties["OutputFABADAChain"] = m_blnManager->addProperty("Output Chain"); - m_properties["FABADAChainLength"] = m_dblManager->addProperty("Chain Length"); - m_dblManager->setDecimals(m_properties["FABADAChainLength"], 0); - m_dblManager->setValue(m_properties["FABADAChainLength"], 10000); - m_properties["FABADAConvergenceCriteria"] = m_dblManager->addProperty("Convergence Criteria"); - m_dblManager->setValue(m_properties["FABADAConvergenceCriteria"], 0.1); - m_properties["FABADAJumpAcceptanceRate"] = m_dblManager->addProperty("Acceptance Rate"); - m_dblManager->setValue(m_properties["FABADAJumpAcceptanceRate"], 0.25); - m_cfTree->addProperty(m_properties["FABADA"]); - - // Background type - m_properties["LinearBackground"] = m_grpManager->addProperty("Background"); - m_properties["BGA0"] = m_dblManager->addProperty("A0"); - m_dblManager->setDecimals(m_properties["BGA0"], NUM_DECIMALS); - m_properties["BGA1"] = m_dblManager->addProperty("A1"); - m_dblManager->setDecimals(m_properties["BGA1"], NUM_DECIMALS); - m_properties["LinearBackground"]->addSubProperty(m_properties["BGA0"]); - m_properties["LinearBackground"]->addSubProperty(m_properties["BGA1"]); - m_cfTree->addProperty(m_properties["LinearBackground"]); - - // Delta Function - m_properties["DeltaFunction"] = m_grpManager->addProperty("Delta Function"); - m_properties["UseDeltaFunc"] = m_blnManager->addProperty("Use"); - m_properties["DeltaHeight"] = m_dblManager->addProperty("Height"); - m_dblManager->setDecimals(m_properties["DeltaHeight"], NUM_DECIMALS); - m_properties["DeltaFunction"]->addSubProperty(m_properties["UseDeltaFunc"]); - m_cfTree->addProperty(m_properties["DeltaFunction"]); - - // Fit functions - m_properties["Lorentzian1"] = createLorentzian("Lorentzian 1"); - m_properties["Lorentzian2"] = createLorentzian("Lorentzian 2"); - m_properties["DiffSphere"] = createDiffSphere("Diffusion Sphere"); - m_properties["DiffRotDiscreteCircle"] = createDiffRotDiscreteCircle("Diffusion Circle"); - - m_uiForm.leTempCorrection->setValidator(new QDoubleValidator(m_parentWidget)); - - // Connections - connect(fitRangeSelector, SIGNAL(minValueChanged(double)), this, SLOT(minChanged(double))); - connect(fitRangeSelector, SIGNAL(maxValueChanged(double)), this, SLOT(maxChanged(double))); - connect(backRangeSelector, SIGNAL(minValueChanged(double)), this, SLOT(backgLevel(double))); - connect(hwhmRangeSelector, SIGNAL(minValueChanged(double)), this, SLOT(hwhmChanged(double))); - connect(hwhmRangeSelector, SIGNAL(maxValueChanged(double)), this, SLOT(hwhmChanged(double))); - connect(m_dblManager, SIGNAL(valueChanged(QtProperty*, double)), this, SLOT(updateRS(QtProperty*, double))); - connect(m_blnManager, SIGNAL(valueChanged(QtProperty*, bool)), this, SLOT(checkBoxUpdate(QtProperty*, bool))); - connect(m_uiForm.ckTempCorrection, SIGNAL(toggled(bool)), m_uiForm.leTempCorrection, SLOT(setEnabled(bool))); - - // Update guess curve when certain things happen - connect(m_dblManager, SIGNAL(propertyChanged(QtProperty*)), this, SLOT(plotGuess())); - connect(m_uiForm.cbFitType, SIGNAL(currentIndexChanged(int)), this, SLOT(plotGuess())); - connect(m_uiForm.ckPlotGuess, SIGNAL(stateChanged(int)), this, SLOT(plotGuess())); - - // Have FWHM Range linked to Fit Start/End Range - connect(fitRangeSelector, SIGNAL(rangeChanged(double, double)), - hwhmRangeSelector, SLOT(setRange(double, double))); - hwhmRangeSelector->setRange(-1.0, 1.0); - hwhmUpdateRS(0.02); - - typeSelection(m_uiForm.cbFitType->currentIndex()); - bgTypeSelection(m_uiForm.cbBackground->currentIndex()); - - // Replot input automatically when file / spec no changes - connect(m_uiForm.spPlotSpectrum, SIGNAL(valueChanged(int)), this, SLOT(updatePlot())); - connect(m_uiForm.dsSampleInput, SIGNAL(dataReady(const QString&)), this, SLOT(newDataLoaded(const QString&))); - - connect(m_uiForm.dsSampleInput, SIGNAL(dataReady(const QString&)), this, SLOT(extendResolutionWorkspace())); - connect(m_uiForm.dsResInput, SIGNAL(dataReady(const QString&)), this, SLOT(extendResolutionWorkspace())); - - connect(m_uiForm.spSpectraMin, SIGNAL(valueChanged(int)), this, SLOT(specMinChanged(int))); - connect(m_uiForm.spSpectraMax, SIGNAL(valueChanged(int)), this, SLOT(specMaxChanged(int))); - - connect(m_uiForm.cbFitType, SIGNAL(currentIndexChanged(int)), this, SLOT(typeSelection(int))); - connect(m_uiForm.cbBackground, SIGNAL(currentIndexChanged(int)), this, SLOT(bgTypeSelection(int))); - connect(m_uiForm.pbSingleFit, SIGNAL(clicked()), this, SLOT(singleFit())); - - // Context menu - m_cfTree->setContextMenuPolicy(Qt::CustomContextMenu); - connect(m_cfTree, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(fitContextMenu(const QPoint &))); - - // Tie - connect(m_uiForm.cbFitType,SIGNAL(currentIndexChanged(QString)),SLOT(showTieCheckbox(QString))); - showTieCheckbox( m_uiForm.cbFitType->currentText() ); +void ConvFit::setup() { + // Create Property Managers + m_stringManager = new QtStringPropertyManager(); + + // Initialise fitTypeStrings + m_fitStrings = QStringList() << "" + << "1L" + << "2L" + << "IDS" + << "IDC" + << "EDS" + << "EDC" + << "SFT"; + + // Create TreeProperty Widget + m_cfTree = new QtTreePropertyBrowser(); + m_uiForm.properties->addWidget(m_cfTree); + + // add factories to managers + m_cfTree->setFactoryForManager(m_blnManager, m_blnEdFac); + m_cfTree->setFactoryForManager(m_dblManager, m_dblEdFac); + + // Create Range Selectors + auto fitRangeSelector = m_uiForm.ppPlot->addRangeSelector("ConvFitRange"); + auto backRangeSelector = m_uiForm.ppPlot->addRangeSelector( + "ConvFitBackRange", MantidWidgets::RangeSelector::YSINGLE); + auto hwhmRangeSelector = m_uiForm.ppPlot->addRangeSelector("ConvFitHWHM"); + backRangeSelector->setColour(Qt::darkGreen); + backRangeSelector->setRange(0.0, 1.0); + hwhmRangeSelector->setColour(Qt::red); + + // Populate Property Widget + + // Option to convolve members + m_properties["Convolve"] = m_blnManager->addProperty("Convolve"); + m_cfTree->addProperty(m_properties["Convolve"]); + m_blnManager->setValue(m_properties["Convolve"], true); + + // Max iterations option + m_properties["MaxIterations"] = m_dblManager->addProperty("Max Iterations"); + m_dblManager->setDecimals(m_properties["MaxIterations"], 0); + m_dblManager->setValue(m_properties["MaxIterations"], 500); + m_cfTree->addProperty(m_properties["MaxIterations"]); + + // Fitting range + m_properties["FitRange"] = m_grpManager->addProperty("Fitting Range"); + m_properties["StartX"] = m_dblManager->addProperty("StartX"); + m_dblManager->setDecimals(m_properties["StartX"], NUM_DECIMALS); + m_properties["EndX"] = m_dblManager->addProperty("EndX"); + m_dblManager->setDecimals(m_properties["EndX"], NUM_DECIMALS); + m_properties["FitRange"]->addSubProperty(m_properties["StartX"]); + m_properties["FitRange"]->addSubProperty(m_properties["EndX"]); + m_cfTree->addProperty(m_properties["FitRange"]); + + // FABADA + m_properties["FABADA"] = m_grpManager->addProperty("Bayesian"); + m_properties["UseFABADA"] = m_blnManager->addProperty("Use FABADA"); + m_properties["FABADA"]->addSubProperty(m_properties["UseFABADA"]); + m_properties["OutputFABADAChain"] = m_blnManager->addProperty("Output Chain"); + m_properties["FABADAChainLength"] = m_dblManager->addProperty("Chain Length"); + m_dblManager->setDecimals(m_properties["FABADAChainLength"], 0); + m_dblManager->setValue(m_properties["FABADAChainLength"], 10000); + m_properties["FABADAConvergenceCriteria"] = + m_dblManager->addProperty("Convergence Criteria"); + m_dblManager->setValue(m_properties["FABADAConvergenceCriteria"], 0.1); + m_properties["FABADAJumpAcceptanceRate"] = + m_dblManager->addProperty("Acceptance Rate"); + m_dblManager->setValue(m_properties["FABADAJumpAcceptanceRate"], 0.25); + m_cfTree->addProperty(m_properties["FABADA"]); + + // Background type + m_properties["LinearBackground"] = m_grpManager->addProperty("Background"); + m_properties["BGA0"] = m_dblManager->addProperty("A0"); + m_dblManager->setDecimals(m_properties["BGA0"], NUM_DECIMALS); + m_properties["BGA1"] = m_dblManager->addProperty("A1"); + m_dblManager->setDecimals(m_properties["BGA1"], NUM_DECIMALS); + m_properties["LinearBackground"]->addSubProperty(m_properties["BGA0"]); + m_properties["LinearBackground"]->addSubProperty(m_properties["BGA1"]); + m_cfTree->addProperty(m_properties["LinearBackground"]); + + // Delta Function + m_properties["DeltaFunction"] = m_grpManager->addProperty("Delta Function"); + m_properties["UseDeltaFunc"] = m_blnManager->addProperty("Use"); + m_properties["DeltaHeight"] = m_dblManager->addProperty("Height"); + m_dblManager->setDecimals(m_properties["DeltaHeight"], NUM_DECIMALS); + m_properties["DeltaFunction"]->addSubProperty(m_properties["UseDeltaFunc"]); + m_cfTree->addProperty(m_properties["DeltaFunction"]); + + // Fit functions + m_properties["Lorentzian1"] = createFitType("Lorentzian 1"); + m_properties["Lorentzian2"] = createFitType("Lorentzian 2"); + m_properties["DiffSphere"] = createFitType("DiffSphere"); + m_properties["DiffRotDiscreteCircle"] = + createFitType("DiffRotDiscreteCircle"); + m_properties["ElasticDiffSphere"] = createFitType("ElasticDiffSphere"); + m_properties["ElasticDiffRotDiscreteCircle"] = + createFitType("ElasticDiffRotDiscreteCircle"); + m_properties["InelasticDiffSphere"] = createFitType("InelasticDiffSphere"); + m_properties["InelasticDiffRotDiscreteCircle"] = + createFitType("InelasticDiffRotDiscreteCircle"); + m_properties["StretchedExpFT"] = createFitType("StretchedExpFT"); + + // Update fit parameters in browser when function is selected + connect(m_uiForm.cbFitType, SIGNAL(currentIndexChanged(QString)), this, + SLOT(fitFunctionSelected(const QString &))); + fitFunctionSelected(m_uiForm.cbFitType->currentText()); + + m_uiForm.leTempCorrection->setValidator(new QDoubleValidator(m_parentWidget)); + + // Connections + connect(fitRangeSelector, SIGNAL(minValueChanged(double)), this, + SLOT(minChanged(double))); + connect(fitRangeSelector, SIGNAL(maxValueChanged(double)), this, + SLOT(maxChanged(double))); + connect(backRangeSelector, SIGNAL(minValueChanged(double)), this, + SLOT(backgLevel(double))); + connect(hwhmRangeSelector, SIGNAL(minValueChanged(double)), this, + SLOT(hwhmChanged(double))); + connect(hwhmRangeSelector, SIGNAL(maxValueChanged(double)), this, + SLOT(hwhmChanged(double))); + connect(m_dblManager, SIGNAL(valueChanged(QtProperty *, double)), this, + SLOT(updateRS(QtProperty *, double))); + connect(m_blnManager, SIGNAL(valueChanged(QtProperty *, bool)), this, + SLOT(checkBoxUpdate(QtProperty *, bool))); + connect(m_uiForm.ckTempCorrection, SIGNAL(toggled(bool)), + m_uiForm.leTempCorrection, SLOT(setEnabled(bool))); + + // Update guess curve when certain things happen + connect(m_dblManager, SIGNAL(propertyChanged(QtProperty *)), this, + SLOT(plotGuess())); + connect(m_uiForm.cbFitType, SIGNAL(currentIndexChanged(int)), this, + SLOT(plotGuess())); + connect(m_uiForm.ckPlotGuess, SIGNAL(stateChanged(int)), this, + SLOT(plotGuess())); + + // Have FWHM Range linked to Fit Start/End Range + connect(fitRangeSelector, SIGNAL(rangeChanged(double, double)), + hwhmRangeSelector, SLOT(setRange(double, double))); + hwhmRangeSelector->setRange(-1.0, 1.0); + hwhmUpdateRS(0.02); + + typeSelection(m_uiForm.cbFitType->currentIndex()); + bgTypeSelection(m_uiForm.cbBackground->currentIndex()); + + // Replot input automatically when file / spec no changes + connect(m_uiForm.spPlotSpectrum, SIGNAL(valueChanged(int)), this, + SLOT(updatePlot())); + connect(m_uiForm.dsSampleInput, SIGNAL(dataReady(const QString &)), this, + SLOT(newDataLoaded(const QString &))); + + connect(m_uiForm.dsSampleInput, SIGNAL(dataReady(const QString &)), this, + SLOT(extendResolutionWorkspace())); + connect(m_uiForm.dsResInput, SIGNAL(dataReady(const QString &)), this, + SLOT(extendResolutionWorkspace())); + + connect(m_uiForm.spSpectraMin, SIGNAL(valueChanged(int)), this, + SLOT(specMinChanged(int))); + connect(m_uiForm.spSpectraMax, SIGNAL(valueChanged(int)), this, + SLOT(specMaxChanged(int))); + + connect(m_uiForm.cbFitType, SIGNAL(currentIndexChanged(int)), this, + SLOT(typeSelection(int))); + connect(m_uiForm.cbBackground, SIGNAL(currentIndexChanged(int)), this, + SLOT(bgTypeSelection(int))); + connect(m_uiForm.pbSingleFit, SIGNAL(clicked()), this, SLOT(singleFit())); + + // Context menu + m_cfTree->setContextMenuPolicy(Qt::CustomContextMenu); + connect(m_cfTree, SIGNAL(customContextMenuRequested(const QPoint &)), this, + SLOT(fitContextMenu(const QPoint &))); + + // Tie + connect(m_uiForm.cbFitType, SIGNAL(currentIndexChanged(QString)), + SLOT(showTieCheckbox(QString))); + showTieCheckbox(m_uiForm.cbFitType->currentText()); + + updatePlotOptions(); +} - updatePlotOptions(); +/** + * Converts data into a python script which prodcues the output workspace + */ +void ConvFit::run() { + if (m_cfInputWS == NULL) { + g_log.error("No workspace loaded"); + return; } + QString fitType = fitTypeString(); + QString bgType = backgroundString(); - void ConvFit::run() - { - if ( m_cfInputWS == NULL ) - { - g_log.error("No workspace loaded"); - return; - } - - QString fitType = fitTypeString(); - QString bgType = backgroundString(); - - if(fitType == "") - { - g_log.error("No fit type defined"); - } - - bool useTies = m_uiForm.ckTieCentres->isChecked(); - QString ties = (useTies ? "True" : "False"); - - CompositeFunction_sptr func = createFunction(useTies); - std::string function = std::string(func->asString()); - QString stX = m_properties["StartX"]->valueText(); - QString enX = m_properties["EndX"]->valueText(); - QString specMin = m_uiForm.spSpectraMin->text(); - QString specMax = m_uiForm.spSpectraMax->text(); - int maxIterations = static_cast<int>(m_dblManager->value(m_properties["MaxIterations"])); - - QString pyInput = - "from IndirectDataAnalysis import confitSeq\n" - "input = '" + m_cfInputWSName + "'\n" - "func = r'" + QString::fromStdString(function) + "'\n" - "startx = " + stX + "\n" - "endx = " + enX + "\n" - "plot = '" + m_uiForm.cbPlotType->currentText() + "'\n" - "ties = " + ties + "\n" - "specMin = " + specMin + "\n" - "specMax = " + specMax + "\n" - "max_iterations = " + QString::number(maxIterations) + "\n" - "minimizer = '" + minimizerString("$outputname_$wsindex") + "'\n" - "save = " + (m_uiForm.ckSave->isChecked() ? "True\n" : "False\n"); - - if ( m_blnManager->value(m_properties["Convolve"]) ) pyInput += "convolve = True\n"; - else pyInput += "convolve = False\n"; - - QString temperature = m_uiForm.leTempCorrection->text(); - bool useTempCorrection = (!temperature.isEmpty() && m_uiForm.ckTempCorrection->isChecked()); - if ( useTempCorrection ) - { - pyInput += "temp=" + temperature + "\n"; - } - else - { - pyInput += "temp=None\n"; - } - - pyInput += - "bg = '" + bgType + "'\n" - "ftype = '" + fitType + "'\n" - "rws = confitSeq(input, func, startx, endx, ftype, bg, temp, specMin, specMax, convolve, max_iterations=max_iterations, minimizer=minimizer, Plot=plot, Save=save)\n" - "AddSampleLog(Workspace=rws, LogName='res_workspace', LogText='" + m_uiForm.dsResInput->getCurrentDataName() + "')\n" - "print rws\n"; + if (fitType == "") { + g_log.error("No fit type defined"); + } - QString pyOutput = runPythonCode(pyInput); + bool useTies = m_uiForm.ckTieCentres->isChecked(); + QString ties = (useTies ? "True" : "False"); + + CompositeFunction_sptr func = createFunction(useTies); + std::string function = std::string(func->asString()); + QString stX = m_properties["StartX"]->valueText(); + QString enX = m_properties["EndX"]->valueText(); + QString specMin = m_uiForm.spSpectraMin->text(); + QString specMax = m_uiForm.spSpectraMax->text(); + int maxIterations = + static_cast<int>(m_dblManager->value(m_properties["MaxIterations"])); + + QString pyInput = "from IndirectDataAnalysis import confitSeq\n" + "input = '" + + m_cfInputWSName + "'\n" + "func = r'" + + QString::fromStdString(function) + "'\n" + "startx = " + + stX + "\n" + "endx = " + + enX + "\n" + "plot = '" + + m_uiForm.cbPlotType->currentText() + "'\n" + "ties = " + + ties + "\n" + "specMin = " + + specMin + "\n" + "specMax = " + + specMax + "\n" + "max_iterations = " + + QString::number(maxIterations) + "\n" + "minimizer = '" + + minimizerString("$outputname_$wsindex") + "'\n" + "save = " + + (m_uiForm.ckSave->isChecked() ? "True\n" : "False\n"); + + if (m_blnManager->value(m_properties["Convolve"])) + pyInput += "convolve = True\n"; + else + pyInput += "convolve = False\n"; + + QString temperature = m_uiForm.leTempCorrection->text(); + bool useTempCorrection = + (!temperature.isEmpty() && m_uiForm.ckTempCorrection->isChecked()); + if (useTempCorrection) { + pyInput += "temp=" + temperature + "\n"; + } else { + pyInput += "temp=None\n"; + } - // Set the result workspace for Python script export - m_pythonExportWsName = pyOutput.toStdString(); + pyInput += "bg = '" + bgType + "'\n" + "ftype = '" + + fitType + + "'\n" + "rws = confitSeq(input, func, startx, endx, ftype, bg, temp, " + "specMin, specMax, convolve, max_iterations=max_iterations, " + "minimizer=minimizer, Plot=plot, Save=save)\n" + "AddSampleLog(Workspace=rws, LogName='res_workspace', LogText='" + + m_uiForm.dsResInput->getCurrentDataName() + "')\n" + "print rws\n"; - updatePlot(); - } + QString pyOutput = runPythonCode(pyInput); + // Set the result workspace for Python script export + m_pythonExportWsName = pyOutput.toStdString(); - /** - * Validates the user's inputs in the ConvFit tab. - */ - bool ConvFit::validate() - { - UserInputValidator uiv; + updatePlot(); +} - uiv.checkDataSelectorIsValid("Sample", m_uiForm.dsSampleInput); - uiv.checkDataSelectorIsValid("Resolution", m_uiForm.dsResInput); +/** + * Validates the user's inputs in the ConvFit tab. + * @return If the validation was successful + */ +bool ConvFit::validate() { + UserInputValidator uiv; - auto range = std::make_pair(m_dblManager->value(m_properties["StartX"]), m_dblManager->value(m_properties["EndX"])); - uiv.checkValidRange("Fitting Range", range); + uiv.checkDataSelectorIsValid("Sample", m_uiForm.dsSampleInput); + uiv.checkDataSelectorIsValid("Resolution", m_uiForm.dsResInput); - // Enforce the rule that at least one fit is needed; either a delta function, one or two lorentzian functions, - // or both. (The resolution function must be convolved with a model.) - if ( m_uiForm.cbFitType->currentIndex() == 0 && ! m_blnManager->value(m_properties["UseDeltaFunc"]) ) - uiv.addErrorMessage("No fit function has been selected."); + auto range = std::make_pair(m_dblManager->value(m_properties["StartX"]), + m_dblManager->value(m_properties["EndX"])); + uiv.checkValidRange("Fitting Range", range); - QString error = uiv.generateErrorMessage(); - showMessageBox(error); + // Enforce the rule that at least one fit is needed; either a delta function, + // one or two lorentzian functions, + // or both. (The resolution function must be convolved with a model.) + if (m_uiForm.cbFitType->currentIndex() == 0 && + !m_blnManager->value(m_properties["UseDeltaFunc"])) + uiv.addErrorMessage("No fit function has been selected."); - return error.isEmpty(); - } + QString error = uiv.generateErrorMessage(); + showMessageBox(error); - void ConvFit::loadSettings(const QSettings & settings) - { - m_uiForm.dsSampleInput->readSettings(settings.group()); - m_uiForm.dsResInput->readSettings(settings.group()); - } + return error.isEmpty(); +} - /** - * Called when new data has been loaded by the data selector. - * - * Configures ranges for spin boxes before raw plot is done. - * - * @param wsName Name of new workspace loaded - */ - void ConvFit::newDataLoaded(const QString wsName) - { - m_cfInputWSName = wsName; - m_cfInputWS = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(m_cfInputWSName.toStdString()); +/** + * Reads in settings files + * @param settings The name of the QSettings object to retrieve data from + */ +void ConvFit::loadSettings(const QSettings &settings) { + m_uiForm.dsSampleInput->readSettings(settings.group()); + m_uiForm.dsResInput->readSettings(settings.group()); +} - int maxSpecIndex = static_cast<int>(m_cfInputWS->getNumberHistograms()) - 1; +/** + * Called when new data has been loaded by the data selector. + * + * Configures ranges for spin boxes before raw plot is done. + * + * @param wsName Name of new workspace loaded + */ +void ConvFit::newDataLoaded(const QString wsName) { + m_cfInputWSName = wsName; + m_cfInputWS = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( + m_cfInputWSName.toStdString()); - m_uiForm.spPlotSpectrum->setMaximum(maxSpecIndex); - m_uiForm.spPlotSpectrum->setMinimum(0); - m_uiForm.spPlotSpectrum->setValue(0); + int maxSpecIndex = static_cast<int>(m_cfInputWS->getNumberHistograms()) - 1; - m_uiForm.spSpectraMin->setMaximum(maxSpecIndex); - m_uiForm.spSpectraMin->setMinimum(0); + m_uiForm.spPlotSpectrum->setMaximum(maxSpecIndex); + m_uiForm.spPlotSpectrum->setMinimum(0); + m_uiForm.spPlotSpectrum->setValue(0); - m_uiForm.spSpectraMax->setMaximum(maxSpecIndex); - m_uiForm.spSpectraMax->setMinimum(0); - m_uiForm.spSpectraMax->setValue(maxSpecIndex); + m_uiForm.spSpectraMin->setMaximum(maxSpecIndex); + m_uiForm.spSpectraMin->setMinimum(0); - updatePlot(); - } + m_uiForm.spSpectraMax->setMaximum(maxSpecIndex); + m_uiForm.spSpectraMax->setMinimum(0); + m_uiForm.spSpectraMax->setValue(maxSpecIndex); + updatePlot(); +} - /** - * Create a resolution workspace with the same number of histograms as in the sample. - * - * Needed to allow DiffSphere and DiffRotDiscreteCircle fit functions to work as they need - * to have the WorkspaceIndex attribute set. - */ - void ConvFit::extendResolutionWorkspace() - { - if(m_cfInputWS && m_uiForm.dsResInput->isValid()) - { - const QString resWsName = m_uiForm.dsResInput->getCurrentDataName(); - - API::BatchAlgorithmRunner::AlgorithmRuntimeProps appendProps; - appendProps["InputWorkspace1"] = "__ConvFit_Resolution"; - - size_t numHist = m_cfInputWS->getNumberHistograms(); - for(size_t i = 0; i < numHist; i++) - { - IAlgorithm_sptr appendAlg = AlgorithmManager::Instance().create("AppendSpectra"); - appendAlg->initialize(); - appendAlg->setProperty("InputWorkspace2", resWsName.toStdString()); - appendAlg->setProperty("OutputWorkspace", "__ConvFit_Resolution"); - - if(i == 0) - { - appendAlg->setProperty("InputWorkspace1", resWsName.toStdString()); - m_batchAlgoRunner->addAlgorithm(appendAlg); - } - else - { - m_batchAlgoRunner->addAlgorithm(appendAlg, appendProps); - } +/** + * Create a resolution workspace with the same number of histograms as in the + * sample. + * + * Needed to allow DiffSphere and DiffRotDiscreteCircle fit functions to work as + * they need + * to have the WorkspaceIndex attribute set. + */ +void ConvFit::extendResolutionWorkspace() { + if (m_cfInputWS && m_uiForm.dsResInput->isValid()) { + const QString resWsName = m_uiForm.dsResInput->getCurrentDataName(); + + API::BatchAlgorithmRunner::AlgorithmRuntimeProps appendProps; + appendProps["InputWorkspace1"] = "__ConvFit_Resolution"; + + size_t numHist = m_cfInputWS->getNumberHistograms(); + for (size_t i = 0; i < numHist; i++) { + IAlgorithm_sptr appendAlg = + AlgorithmManager::Instance().create("AppendSpectra"); + appendAlg->initialize(); + appendAlg->setProperty("InputWorkspace2", resWsName.toStdString()); + appendAlg->setProperty("OutputWorkspace", "__ConvFit_Resolution"); + + if (i == 0) { + appendAlg->setProperty("InputWorkspace1", resWsName.toStdString()); + m_batchAlgoRunner->addAlgorithm(appendAlg); + } else { + m_batchAlgoRunner->addAlgorithm(appendAlg, appendProps); } - - m_batchAlgoRunner->executeBatchAsync(); } - } + m_batchAlgoRunner->executeBatchAsync(); + } +} - namespace - { - //////////////////////////// - // Anon Helper functions. // - //////////////////////////// - - /** - * Takes an index and a name, and constructs a single level parameter name - * for use with function ties, etc. - * - * @param index :: the index of the function in the first level. - * @param name :: the name of the parameter inside the function. - * - * @returns the constructed function parameter name. - */ - std::string createParName(size_t index, const std::string & name = "") - { - std::stringstream prefix; - prefix << "f" << index << "." << name; - return prefix.str(); - } +namespace { +//////////////////////////// +// Anon Helper functions. // +//////////////////////////// + +/** + * Takes an index and a name, and constructs a single level parameter name + * for use with function ties, etc. + * + * @param index :: the index of the function in the first level. + * @param name :: the name of the parameter inside the function. + * + * @returns the constructed function parameter name. + */ +std::string createParName(size_t index, const std::string &name = "") { + std::stringstream prefix; + prefix << "f" << index << "." << name; + return prefix.str(); +} +/** + * Takes an index, a sub index and a name, and constructs a double level + * (nested) parameter name for use with function ties, etc. + * + * @param index :: the index of the function in the first level. + * @param subIndex :: the index of the function in the second level. + * @param name :: the name of the parameter inside the function. + * + * @returns the constructed function parameter name. + */ +std::string createParName(size_t index, size_t subIndex, + const std::string &name = "") { + std::stringstream prefix; + prefix << "f" << index << ".f" << subIndex << "." << name; + return prefix.str(); +} +} - /** - * Takes an index, a sub index and a name, and constructs a double level - * (nested) parameter name for use with function ties, etc. - * - * @param index :: the index of the function in the first level. - * @param subIndex :: the index of the function in the second level. - * @param name :: the name of the parameter inside the function. - * - * @returns the constructed function parameter name. - */ - std::string createParName(size_t index, size_t subIndex, const std::string & name = "") - { - std::stringstream prefix; - prefix << "f" << index << ".f" << subIndex << "." << name; - return prefix.str(); - } +/** + * Creates a function to carry out the fitting in the "ConvFit" tab. The + * function consists of various sub functions, with the following structure: + * + * Composite + * | + * +- LinearBackground + * +- Convolution + * | + * +- Resolution + * +- Model (AT LEAST one delta function or one/two lorentzians.) + * | + * +- DeltaFunction(yes/no) + * +- ProductFunction + * | + * +- Lorentzian 1(yes/no) + * +- Temperature Correction(yes/no) + * +- ProductFunction + * | + * +- Lorentzian 2(yes/no) + * +- Temperature Correction(yes/no) + * +- ProductFunction + * | + * +- InelasticDiffSphere(yes/no) + * +- Temperature Correction(yes/no) + * +- ProductFunction + * | + * +- InelasticDiffRotDiscreteCircle(yes/no) + * +- Temperature Correction(yes/no) + * + * @param tieCentres :: whether to tie centres of the two lorentzians. + * + * @returns the composite fitting function. + */ +CompositeFunction_sptr ConvFit::createFunction(bool tieCentres) { + auto conv = boost::dynamic_pointer_cast<CompositeFunction>( + FunctionFactory::Instance().createFunction("Convolution")); + CompositeFunction_sptr comp(new CompositeFunction); + + IFunction_sptr func; + size_t index = 0; + + // ------------------------------------- + // --- Composite / Linear Background --- + // ------------------------------------- + func = FunctionFactory::Instance().createFunction("LinearBackground"); + comp->addFunction(func); + + // 0 = Fixed Flat, 1 = Fit Flat, 2 = Fit all + const int bgType = m_uiForm.cbBackground->currentIndex(); + + if (bgType == 0 || !m_properties["BGA0"]->subProperties().isEmpty()) { + comp->tie("f0.A0", m_properties["BGA0"]->valueText().toStdString()); + } else { + func->setParameter("A0", m_properties["BGA0"]->valueText().toDouble()); } - - /** - * Creates a function to carry out the fitting in the "ConvFit" tab. The function consists - * of various sub functions, with the following structure: - * - * Composite - * | - * +-- LinearBackground - * +-- Convolution - * | - * +-- Resolution - * +-- Model (AT LEAST one delta function or one/two lorentzians.) - * | - * +-- DeltaFunction (yes/no) - * +-- ProductFunction - * | - * +-- Lorentzian 1 (yes/no) - * +-- Temperature Correction (yes/no) - * +-- ProductFunction - * | - * +-- Lorentzian 2 (yes/no) - * +-- Temperature Correction (yes/no) - * +-- ProductFunction - * | - * +-- InelasticDiffSphere (yes/no) - * +-- Temperature Correction (yes/no) - * +-- ProductFunction - * | - * +-- InelasticDiffRotDiscreteCircle (yes/no) - * +-- Temperature Correction (yes/no) - * - * @param tieCentres :: whether to tie centres of the two lorentzians. - * - * @returns the composite fitting function. - */ - CompositeFunction_sptr ConvFit::createFunction(bool tieCentres) - { - auto conv = boost::dynamic_pointer_cast<CompositeFunction>(FunctionFactory::Instance().createFunction("Convolution")); - CompositeFunction_sptr comp( new CompositeFunction ); - - IFunction_sptr func; - size_t index = 0; - - // ------------------------------------- - // --- Composite / Linear Background --- - // ------------------------------------- - func = FunctionFactory::Instance().createFunction("LinearBackground"); - comp->addFunction(func); - - const int bgType = m_uiForm.cbBackground->currentIndex(); // 0 = Fixed Flat, 1 = Fit Flat, 2 = Fit all - - if ( bgType == 0 || ! m_properties["BGA0"]->subProperties().isEmpty() ) - { - comp->tie("f0.A0", m_properties["BGA0"]->valueText().toStdString() ); - } - else - { - func->setParameter("A0", m_properties["BGA0"]->valueText().toDouble()); - } - - if ( bgType != 2 ) - { - comp->tie("f0.A1", "0.0"); - } - else - { - if ( ! m_properties["BGA1"]->subProperties().isEmpty() ) - { - comp->tie("f0.A1", m_properties["BGA1"]->valueText().toStdString() ); - } - else { func->setParameter("A1", m_properties["BGA1"]->valueText().toDouble()); } + if (bgType != 2) { + comp->tie("f0.A1", "0.0"); + } else { + if (!m_properties["BGA1"]->subProperties().isEmpty()) { + comp->tie("f0.A1", m_properties["BGA1"]->valueText().toStdString()); + } else { + func->setParameter("A1", m_properties["BGA1"]->valueText().toDouble()); } + } - // -------------------------------------------- - // --- Composite / Convolution / Resolution --- - // -------------------------------------------- - func = FunctionFactory::Instance().createFunction("Resolution"); - conv->addFunction(func); + // -------------------------------------------- + // --- Composite / Convolution / Resolution --- + // -------------------------------------------- + func = FunctionFactory::Instance().createFunction("Resolution"); + conv->addFunction(func); + + // add resolution file + IFunction::Attribute attr("__ConvFit_Resolution"); + func->setAttribute("Workspace", attr); + + // -------------------------------------------------------- + // --- Composite / Convolution / Model / Delta Function --- + // -------------------------------------------------------- + CompositeFunction_sptr model(new CompositeFunction); + + bool useDeltaFunc = m_blnManager->value(m_properties["UseDeltaFunc"]); + + if (useDeltaFunc) { + func = FunctionFactory::Instance().createFunction("DeltaFunction"); + index = model->addFunction(func); + std::string parName = createParName(index); + populateFunction(func, model, m_properties["DeltaFunction"], parName, + false); + } - //add resolution file - IFunction::Attribute attr("__ConvFit_Resolution"); - func->setAttribute("Workspace", attr); + // ------------------------------------------------------------ + // --- Composite / Convolution / Model / Temperature Factor --- + // ------------------------------------------------------------ - // -------------------------------------------------------- - // --- Composite / Convolution / Model / Delta Function --- - // -------------------------------------------------------- - CompositeFunction_sptr model( new CompositeFunction ); + // create temperature correction function to multiply with the lorentzians + IFunction_sptr tempFunc; + QString temperature = m_uiForm.leTempCorrection->text(); + bool useTempCorrection = + (!temperature.isEmpty() && m_uiForm.ckTempCorrection->isChecked()); - bool useDeltaFunc = m_blnManager->value(m_properties["UseDeltaFunc"]); + // ----------------------------------------------------- + // --- Composite / Convolution / Model / Lorentzians --- + // ----------------------------------------------------- + std::string prefix1; + std::string prefix2; + int fitTypeIndex = m_uiForm.cbFitType->currentIndex(); + if (fitTypeIndex > 0) { size_t subIndex = 0; + auto product = boost::dynamic_pointer_cast<CompositeFunction>( + FunctionFactory::Instance().createFunction("ProductFunction")); - if ( useDeltaFunc ) - { - func = FunctionFactory::Instance().createFunction("DeltaFunction"); - index = model->addFunction(func); - std::string parName = createParName(index); - populateFunction(func, model, m_properties["DeltaFunction"], parName, false); + if (useTempCorrection) { + createTemperatureCorrection(product); } - // ------------------------------------------------------------ - // --- Composite / Convolution / Model / Temperature Factor --- - // ------------------------------------------------------------ - - //create temperature correction function to multiply with the lorentzians - IFunction_sptr tempFunc; - QString temperature = m_uiForm.leTempCorrection->text(); - bool useTempCorrection = (!temperature.isEmpty() && m_uiForm.ckTempCorrection->isChecked()); - - // ----------------------------------------------------- - // --- Composite / Convolution / Model / Lorentzians --- - // ----------------------------------------------------- - std::string prefix1; - std::string prefix2; - - int fitTypeIndex = m_uiForm.cbFitType->currentIndex(); - // Add 1st Lorentzian - if(fitTypeIndex == 1 || fitTypeIndex == 2) - { - //if temperature not included then product is lorentzian * 1 - //create product function for temp * lorentzian - auto product = boost::dynamic_pointer_cast<CompositeFunction>(FunctionFactory::Instance().createFunction("ProductFunction")); - - if(useTempCorrection) - { - createTemperatureCorrection(product); - } - func = FunctionFactory::Instance().createFunction("Lorentzian"); - subIndex = product->addFunction(func); - index = model->addFunction(product); - prefix1 = createParName(index, subIndex); - - populateFunction(func, model, m_properties["Lorentzian1"], prefix1, false); - } + // if temperature not included then product is lorentzian * 1 + // create product function for temp * lorentzian - // Add 2nd Lorentzian - if(fitTypeIndex == 2) - { - //if temperature not included then product is lorentzian * 1 - //create product function for temp * lorentzian - auto product = boost::dynamic_pointer_cast<CompositeFunction>(FunctionFactory::Instance().createFunction("ProductFunction")); - - if(useTempCorrection) - { - createTemperatureCorrection(product); - } + std::string functionName = m_uiForm.cbFitType->currentText().toStdString(); - func = FunctionFactory::Instance().createFunction("Lorentzian"); - subIndex = product->addFunction(func); - index = model->addFunction(product); - prefix2 = createParName(index, subIndex); - - populateFunction(func, model, m_properties["Lorentzian2"], prefix2, false); + if (fitTypeIndex == 1 || fitTypeIndex == 2) { + functionName = "Lorentzian"; } + func = FunctionFactory::Instance().createFunction(functionName); + subIndex = product->addFunction(func); + index = model->addFunction(product); + prefix1 = createParName(index, subIndex); - // ------------------------------------------------------------- - // --- Composite / Convolution / Model / InelasticDiffSphere --- - // ------------------------------------------------------------- - if(fitTypeIndex == 3) - { - auto product = boost::dynamic_pointer_cast<CompositeFunction>(FunctionFactory::Instance().createFunction("ProductFunction")); - - if(useTempCorrection) - { - createTemperatureCorrection(product); - } - - func = FunctionFactory::Instance().createFunction("InelasticDiffSphere"); - subIndex = product->addFunction(func); - index = model->addFunction(product); - prefix2 = createParName(index, subIndex); - - populateFunction(func, model, m_properties["DiffSphere"], prefix2, false); - } + populateFunction(func, model, m_properties["FitFunction1"], prefix1, false); - // ------------------------------------------------------------------------ - // --- Composite / Convolution / Model / InelasticDiffRotDiscreteCircle --- - // ------------------------------------------------------------------------ - if(fitTypeIndex == 4) - { - auto product = boost::dynamic_pointer_cast<CompositeFunction>(FunctionFactory::Instance().createFunction("ProductFunction")); + // Add 2nd Lorentzian + if (fitTypeIndex == 2) { + // if temperature not included then product is lorentzian * 1 + // create product function for temp * lorentzian + auto product = boost::dynamic_pointer_cast<CompositeFunction>( + FunctionFactory::Instance().createFunction("ProductFunction")); - if(useTempCorrection) - { + if (useTempCorrection) { createTemperatureCorrection(product); } - func = FunctionFactory::Instance().createFunction("InelasticDiffRotDiscreteCircle"); + func = FunctionFactory::Instance().createFunction(functionName); subIndex = product->addFunction(func); index = model->addFunction(product); prefix2 = createParName(index, subIndex); - populateFunction(func, model, m_properties["DiffRotDiscreteCircle"], prefix2, false); - } - - conv->addFunction(model); - comp->addFunction(conv); - - // Tie PeakCentres together - if ( tieCentres ) - { - std::string tieL = prefix1 + "PeakCentre"; - std::string tieR = prefix2 + "PeakCentre"; - model->tie(tieL, tieR); + populateFunction(func, model, m_properties["FitFunction2"], prefix2, + false); } - - comp->applyTies(); - return comp; } + conv->addFunction(model); + comp->addFunction(conv); - void ConvFit::createTemperatureCorrection(CompositeFunction_sptr product) - { - //create temperature correction function to multiply with the lorentzians - IFunction_sptr tempFunc; - QString temperature = m_uiForm.leTempCorrection->text(); - - //create user function for the exponential correction - // (x*temp) / 1-exp(-(x*temp)) - tempFunc = FunctionFactory::Instance().createFunction("UserFunction"); - //11.606 is the conversion factor from meV to K - std::string formula = "((x*11.606)/Temp) / (1 - exp(-((x*11.606)/Temp)))"; - IFunction::Attribute att(formula); - tempFunc->setAttribute("Formula", att); - tempFunc->setParameter("Temp", temperature.toDouble()); - - product->addFunction(tempFunc); - product->tie("f0.Temp", temperature.toStdString()); - product->applyTies(); + // Tie PeakCentres together + if (tieCentres) { + std::string tieL = prefix1 + "PeakCentre"; + std::string tieR = prefix2 + "PeakCentre"; + model->tie(tieL, tieR); } + comp->applyTies(); + return comp; +} + +/** + * Creates the correction for the temperature + */ +void ConvFit::createTemperatureCorrection(CompositeFunction_sptr product) { + // create temperature correction function to multiply with the lorentzians + IFunction_sptr tempFunc; + QString temperature = m_uiForm.leTempCorrection->text(); + + // create user function for the exponential correction + // (x*temp) / 1-exp(-(x*temp)) + tempFunc = FunctionFactory::Instance().createFunction("UserFunction"); + // 11.606 is the conversion factor from meV to K + std::string formula = "((x*11.606)/Temp) / (1 - exp(-((x*11.606)/Temp)))"; + IFunction::Attribute att(formula); + tempFunc->setAttribute("Formula", att); + tempFunc->setParameter("Temp", temperature.toDouble()); + + product->addFunction(tempFunc); + product->tie("f0.Temp", temperature.toStdString()); + product->applyTies(); +} - double ConvFit::getInstrumentResolution(std::string workspaceName) - { - using namespace Mantid::API; +/** + * Obtains the instrument resolution from the provided workspace + * @param workspaceName The name of the workspaces which holds the instrument + * resolution + * @return The resolution of the instrument. returns 0 if no resolution data + * could be found + */ +double ConvFit::getInstrumentResolution(std::string workspaceName) { + using namespace Mantid::API; + + double resolution = 0.0; + try { + Mantid::Geometry::Instrument_const_sptr inst = + AnalysisDataService::Instance() + .retrieveWS<MatrixWorkspace>(workspaceName) + ->getInstrument(); + std::vector<std::string> analysers = inst->getStringParameter("analyser"); + if (analysers.empty()) { + g_log.warning("Could not load instrument resolution from parameter file"); + return 0.0; + } - double resolution = 0.0; - try - { - Mantid::Geometry::Instrument_const_sptr inst = - AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(workspaceName)->getInstrument(); - std::vector<std::string> analysers = inst->getStringParameter("analyser"); - if(analysers.empty()) - { - g_log.warning("Could not load instrument resolution from parameter file"); + std::string analyser = analysers[0]; + std::string idfDirectory = + Mantid::Kernel::ConfigService::Instance().getString( + "instrumentDefinition.directory"); + + // If the analyser component is not already in the data file then load it + // from the parameter file + if (inst->getComponentByName(analyser) + ->getNumberParameter("resolution") + .size() == 0) { + std::string reflection = inst->getStringParameter("reflection")[0]; + + IAlgorithm_sptr loadParamFile = + AlgorithmManager::Instance().create("LoadParameterFile"); + loadParamFile->initialize(); + loadParamFile->setProperty("Workspace", workspaceName); + loadParamFile->setProperty( + "Filename", idfDirectory + inst->getName() + "_" + analyser + "_" + + reflection + "_Parameters.xml"); + loadParamFile->execute(); + + if (!loadParamFile->isExecuted()) { + g_log.warning("Could not load parameter file, ensure instrument " + "directory is in data search paths."); return 0.0; } - std::string analyser = analysers[0]; - std::string idfDirectory = Mantid::Kernel::ConfigService::Instance().getString("instrumentDefinition.directory"); - - // If the analyser component is not already in the data file the laod it from the parameter file - if(inst->getComponentByName(analyser)->getNumberParameter("resolution").size() == 0) - { - std::string reflection = inst->getStringParameter("reflection")[0]; + inst = AnalysisDataService::Instance() + .retrieveWS<MatrixWorkspace>(workspaceName) + ->getInstrument(); + } - IAlgorithm_sptr loadParamFile = AlgorithmManager::Instance().create("LoadParameterFile"); - loadParamFile->initialize(); - loadParamFile->setProperty("Workspace", workspaceName); - loadParamFile->setProperty("Filename", idfDirectory + inst->getName() + "_"+analyser + "_" + reflection + "_Parameters.xml"); - loadParamFile->execute(); + resolution = + inst->getComponentByName(analyser)->getNumberParameter("resolution")[0]; + } catch (Mantid::Kernel::Exception::NotFoundError &e) { + UNUSED_ARG(e); - if(!loadParamFile->isExecuted()) - { - g_log.warning("Could not load parameter file, ensure instrument directory is in data search paths."); - return 0.0; - } + g_log.warning("Could not load instrument resolution from parameter file"); + resolution = 0.0; + } - inst = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(workspaceName)->getInstrument(); - } + return resolution; +} - resolution = inst->getComponentByName(analyser)->getNumberParameter("resolution")[0]; +/** + * Intialises the property values for any of the fit type + * @param propName The name of the property group + * @return The popuated property group representing a fit type + */ +QtProperty *ConvFit::createFitType(const QString &propName) { + QtProperty *fitTypeGroup = m_grpManager->addProperty(propName); + QString cbName = propName; + if (propName.compare("Lorentzian 1") == 0) { + cbName = "One Lorentzian"; + } + if (propName.compare("Lorentzian 2") == 0) { + cbName = "Two Lorentzians"; + } + auto params = getFunctionParameters(cbName); + + for (auto it = params.begin(); it != params.end(); ++it) { + QString paramName = propName + "." + *it; + m_properties[paramName] = m_dblManager->addProperty(*it); + m_dblManager->setDecimals(m_properties[paramName], NUM_DECIMALS); + if (QString(*it).compare("FWHM") == 0) { + m_dblManager->setValue(m_properties[paramName], 0.02); } - catch(Mantid::Kernel::Exception::NotFoundError &e) - { - UNUSED_ARG(e); + fitTypeGroup->addSubProperty(m_properties[paramName]); + } + return fitTypeGroup; +} - g_log.warning("Could not load instrument resolution from parameter file"); - resolution = 0.0; +/** + * Populates the properties of a function with given values + * @param func The function currently being added to the composite + * @param comp A composite function of the previously called functions + * @param group The QtProperty representing the fit type + * @param pref The index of the functions eg. (f0.f1) + * @param tie Bool to state if parameters are to be tied together + */ +void ConvFit::populateFunction(IFunction_sptr func, IFunction_sptr comp, + QtProperty *group, const std::string &pref, + bool tie) { + // Get subproperties of group and apply them as parameters on the function + // object + QList<QtProperty *> props = group->subProperties(); + + for (int i = 0; i < props.size(); i++) { + if (tie || !props[i]->subProperties().isEmpty()) { + std::string name = pref + props[i]->propertyName().toStdString(); + std::string value = props[i]->valueText().toStdString(); + comp->tie(name, value); + } else { + std::string propName = props[i]->propertyName().toStdString(); + double propValue = props[i]->valueText().toDouble(); + if (propValue) { + if (func->hasAttribute(propName)) + func->setAttributeValue(propName, propValue); + else + func->setParameter(propName, propValue); + } } - - return resolution; } +} +/** + * Generate a string to describe the fit type selected by the user. + * Used when naming the resultant workspaces. + * + * Assertions used to guard against any future changes that dont take + * workspace naming into account. + * + * @returns the generated QString. + */ +QString ConvFit::fitTypeString() const { + QString fitType(""); - QtProperty* ConvFit::createLorentzian(const QString & name) - { - QtProperty* lorentzGroup = m_grpManager->addProperty(name); - - m_properties[name+".Amplitude"] = m_dblManager->addProperty("Amplitude"); - // m_dblManager->setRange(m_properties[name+".Amplitude"], 0.0, 1.0); // 0 < Amplitude < 1 - m_properties[name+".PeakCentre"] = m_dblManager->addProperty("PeakCentre"); - m_properties[name+".FWHM"] = m_dblManager->addProperty("FWHM"); + if (m_blnManager->value(m_properties["UseDeltaFunc"])) + fitType += "Delta"; - m_dblManager->setDecimals(m_properties[name+".Amplitude"], NUM_DECIMALS); - m_dblManager->setDecimals(m_properties[name+".PeakCentre"], NUM_DECIMALS); - m_dblManager->setDecimals(m_properties[name+".FWHM"], NUM_DECIMALS); - m_dblManager->setValue(m_properties[name+".FWHM"], 0.02); + fitType += m_fitStrings.at(m_uiForm.cbFitType->currentIndex()); - lorentzGroup->addSubProperty(m_properties[name+".Amplitude"]); - lorentzGroup->addSubProperty(m_properties[name+".PeakCentre"]); - lorentzGroup->addSubProperty(m_properties[name+".FWHM"]); + return fitType; +} - return lorentzGroup; +/** + * Generate a string to describe the background selected by the user. + * Used when naming the resultant workspaces. + * + * Assertions used to guard against any future changes that dont take + * workspace naming into account. + * + * @returns the generated QString. + */ +QString ConvFit::backgroundString() const { + switch (m_uiForm.cbBackground->currentIndex()) { + case 0: + return "FixF_s"; + case 1: + return "FitF_s"; + case 2: + return "FitL_s"; + default: + return ""; } +} +/** + * Generates a string that defines the fitting minimizer based on the user + * options. + * + * @return Minimizer as a string + */ +QString ConvFit::minimizerString(QString outputName) const { + QString minimizer = "Levenberg-Marquardt"; - QtProperty* ConvFit::createDiffSphere(const QString & name) - { - QtProperty* diffSphereGroup = m_grpManager->addProperty(name); - - m_properties[name+".Intensity"] = m_dblManager->addProperty("Intensity"); - m_properties[name+".Radius"] = m_dblManager->addProperty("Radius"); - m_properties[name+".Diffusion"] = m_dblManager->addProperty("Diffusion"); - m_properties[name+".Shift"] = m_dblManager->addProperty("Shift"); - - m_dblManager->setDecimals(m_properties[name+".Intensity"], NUM_DECIMALS); - m_dblManager->setDecimals(m_properties[name+".Radius"], NUM_DECIMALS); - m_dblManager->setDecimals(m_properties[name+".Diffusion"], NUM_DECIMALS); - m_dblManager->setDecimals(m_properties[name+".Shift"], NUM_DECIMALS); + if (m_blnManager->value(m_properties["UseFABADA"])) { + minimizer = "FABADA"; - diffSphereGroup->addSubProperty(m_properties[name+".Intensity"]); - diffSphereGroup->addSubProperty(m_properties[name+".Radius"]); - diffSphereGroup->addSubProperty(m_properties[name+".Diffusion"]); - diffSphereGroup->addSubProperty(m_properties[name+".Shift"]); + int chainLength = static_cast<int>( + m_dblManager->value(m_properties["FABADAChainLength"])); + minimizer += ",ChainLength=" + QString::number(chainLength); - return diffSphereGroup; - } + double convergenceCriteria = + m_dblManager->value(m_properties["FABADAConvergenceCriteria"]); + minimizer += ",ConvergenceCriteria=" + QString::number(convergenceCriteria); + double jumpAcceptanceRate = + m_dblManager->value(m_properties["FABADAJumpAcceptanceRate"]); + minimizer += ",JumpAcceptanceRate=" + QString::number(jumpAcceptanceRate); - QtProperty* ConvFit::createDiffRotDiscreteCircle(const QString & name) - { - QtProperty* diffRotDiscreteCircleGroup = m_grpManager->addProperty(name); + minimizer += ",PDF=" + outputName + "_PDF"; - m_properties[name+".N"] = m_dblManager->addProperty("N"); - m_dblManager->setValue(m_properties[name+".N"], 3.0); + if (m_blnManager->value(m_properties["OutputFABADAChain"])) + minimizer += ",Chains=" + outputName + "_Chain"; + } - m_properties[name+".Intensity"] = m_dblManager->addProperty("Intensity"); - m_properties[name+".Radius"] = m_dblManager->addProperty("Radius"); - m_properties[name+".Decay"] = m_dblManager->addProperty("Decay"); - m_properties[name+".Shift"] = m_dblManager->addProperty("Shift"); + return minimizer; +} - m_dblManager->setDecimals(m_properties[name+".N"], 0); - m_dblManager->setDecimals(m_properties[name+".Intensity"], NUM_DECIMALS); - m_dblManager->setDecimals(m_properties[name+".Radius"], NUM_DECIMALS); - m_dblManager->setDecimals(m_properties[name+".Decay"], NUM_DECIMALS); - m_dblManager->setDecimals(m_properties[name+".Shift"], NUM_DECIMALS); +/** + * Changes property tree and plot appearance based on Fit Type + * @param index A reference to the Fit Type (0-9) + */ +void ConvFit::typeSelection(int index) { - diffRotDiscreteCircleGroup->addSubProperty(m_properties[name+".N"]); - diffRotDiscreteCircleGroup->addSubProperty(m_properties[name+".Intensity"]); - diffRotDiscreteCircleGroup->addSubProperty(m_properties[name+".Radius"]); - diffRotDiscreteCircleGroup->addSubProperty(m_properties[name+".Decay"]); - diffRotDiscreteCircleGroup->addSubProperty(m_properties[name+".Shift"]); + auto hwhmRangeSelector = m_uiForm.ppPlot->getRangeSelector("ConvFitHWHM"); - return diffRotDiscreteCircleGroup; + if (index == 0) { + hwhmRangeSelector->setVisible(false); + } else if (index < 3) { + hwhmRangeSelector->setVisible(true); + } else { + hwhmRangeSelector->setVisible(false); + m_uiForm.ckPlotGuess->setChecked(false); + m_blnManager->setValue(m_properties["UseDeltaFunc"], false); } + // Disable Plot Guess and Use Delta Function for DiffSphere and + // DiffRotDiscreteCircle + m_uiForm.ckPlotGuess->setEnabled(index < 3); + m_properties["UseDeltaFunc"]->setEnabled(index < 3); - void ConvFit::populateFunction(IFunction_sptr func, IFunction_sptr comp, QtProperty* group, const std::string & pref, bool tie) - { - // Get subproperties of group and apply them as parameters on the function object - QList<QtProperty*> props = group->subProperties(); + updatePlotOptions(); +} - for ( int i = 0; i < props.size(); i++ ) - { - if ( tie || ! props[i]->subProperties().isEmpty() ) - { - std::string name = pref + props[i]->propertyName().toStdString(); - std::string value = props[i]->valueText().toStdString(); - comp->tie(name, value); - } - else - { - std::string propName = props[i]->propertyName().toStdString(); - double propValue = props[i]->valueText().toDouble(); - if(propValue) - { - if(func->hasAttribute(propName)) - func->setAttributeValue(propName, propValue); - else - func->setParameter(propName, propValue); - } - } - } +/** + * Add/Remove sub property 'BGA1' from background based on Background type + * @param index A reference to the Background type + */ +void ConvFit::bgTypeSelection(int index) { + if (index == 2) { + m_properties["LinearBackground"]->addSubProperty(m_properties["BGA1"]); + } else { + m_properties["LinearBackground"]->removeSubProperty(m_properties["BGA1"]); } +} +/** + * Updates the plot in the gui window + */ +void ConvFit::updatePlot() { + using Mantid::Kernel::Exception::NotFoundError; - /** - * Generate a string to describe the fit type selected by the user. - * Used when naming the resultant workspaces. - * - * Assertions used to guard against any future changes that dont take - * workspace naming into account. - * - * @returns the generated QString. - */ - QString ConvFit::fitTypeString() const - { - QString fitType(""); - - if( m_blnManager->value(m_properties["UseDeltaFunc"]) ) - fitType += "Delta"; - - switch ( m_uiForm.cbFitType->currentIndex() ) - { - case 0: - break; - case 1: - fitType += "1L"; break; - case 2: - fitType += "2L"; break; - case 3: - fitType += "DS"; break; - case 4: - fitType += "DC"; break; - } - - return fitType; + if (!m_cfInputWS) { + g_log.error("No workspace loaded, cannot create preview plot."); + return; } + bool plotGuess = m_uiForm.ckPlotGuess->isChecked(); + m_uiForm.ckPlotGuess->setChecked(false); - /** - * Generate a string to describe the background selected by the user. - * Used when naming the resultant workspaces. - * - * Assertions used to guard against any future changes that dont take - * workspace naming into account. - * - * @returns the generated QString. - */ - QString ConvFit::backgroundString() const - { - switch ( m_uiForm.cbBackground->currentIndex() ) - { - case 0: - return "FixF_s"; - case 1: - return "FitF_s"; - case 2: - return "FitL_s"; - default: - return ""; - } - } + int specNo = m_uiForm.spPlotSpectrum->text().toInt(); + m_uiForm.ppPlot->clear(); + m_uiForm.ppPlot->addSpectrum("Sample", m_cfInputWS, specNo); - /** - * Generates a string that defines the fitting minimizer based on the user - * options. - * - * @return Minimizer as a string - */ - QString ConvFit::minimizerString(QString outputName) const - { - QString minimizer = "Levenberg-Marquardt"; + try { + const QPair<double, double> curveRange = + m_uiForm.ppPlot->getCurveRange("Sample"); + const std::pair<double, double> range(curveRange.first, curveRange.second); + m_uiForm.ppPlot->getRangeSelector("ConvFitRange") + ->setRange(range.first, range.second); + m_uiForm.ckPlotGuess->setChecked(plotGuess); + } catch (std::invalid_argument &exc) { + showMessageBox(exc.what()); + } - if(m_blnManager->value(m_properties["UseFABADA"])) - { - minimizer = "FABADA"; + // Default FWHM to resolution of instrument + double resolution = getInstrumentResolution(m_cfInputWSName.toStdString()); + if (resolution > 0) { + m_dblManager->setValue(m_properties["Lorentzian 1.FWHM"], resolution); + m_dblManager->setValue(m_properties["Lorentzian 2.FWHM"], resolution); + } - int chainLength = static_cast<int>(m_dblManager->value(m_properties["FABADAChainLength"])); - minimizer += ",ChainLength=" + QString::number(chainLength); + // If there is a result plot then plot it + if (AnalysisDataService::Instance().doesExist(m_pythonExportWsName)) { + WorkspaceGroup_sptr outputGroup = + AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>( + m_pythonExportWsName); + if (specNo >= static_cast<int>(outputGroup->size())) + return; + MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast<MatrixWorkspace>( + outputGroup->getItem(specNo)); + if (ws) + m_uiForm.ppPlot->addSpectrum("Fit", ws, 1, Qt::red); + } +} - double convergenceCriteria = m_dblManager->value(m_properties["FABADAConvergenceCriteria"]); - minimizer += ",ConvergenceCriteria=" + QString::number(convergenceCriteria); +/** + * Updates the guess for the plot + */ +void ConvFit::plotGuess() { + m_uiForm.ppPlot->removeSpectrum("Guess"); - double jumpAcceptanceRate = m_dblManager->value(m_properties["FABADAJumpAcceptanceRate"]); - minimizer += ",JumpAcceptanceRate=" + QString::number(jumpAcceptanceRate); + // Do nothing if there is not a sample and resolution + if (!(m_uiForm.dsSampleInput->isValid() && m_uiForm.dsResInput->isValid() && + m_uiForm.ckPlotGuess->isChecked())) + return; - minimizer += ",PDF=" + outputName + "_PDF"; + if(m_uiForm.cbFitType->currentIndex() > 2){ + return; + } - if(m_blnManager->value(m_properties["OutputFABADAChain"])) - minimizer += ",Chains=" + outputName + "_Chain"; - } + bool tieCentres = (m_uiForm.cbFitType->currentIndex() > 1); + CompositeFunction_sptr function = createFunction(tieCentres); - return minimizer; + if (m_cfInputWS == NULL) { + updatePlot(); } - - void ConvFit::typeSelection(int index) - { - m_cfTree->removeProperty(m_properties["Lorentzian1"]); - m_cfTree->removeProperty(m_properties["Lorentzian2"]); - m_cfTree->removeProperty(m_properties["DiffSphere"]); - m_cfTree->removeProperty(m_properties["DiffRotDiscreteCircle"]); - - auto hwhmRangeSelector = m_uiForm.ppPlot->getRangeSelector("ConvFitHWHM"); - - switch ( index ) - { - case 0: - hwhmRangeSelector->setVisible(false); - break; - case 1: - m_cfTree->addProperty(m_properties["Lorentzian1"]); - hwhmRangeSelector->setVisible(true); - break; - case 2: - m_cfTree->addProperty(m_properties["Lorentzian1"]); - m_cfTree->addProperty(m_properties["Lorentzian2"]); - hwhmRangeSelector->setVisible(true); - break; - case 3: - m_cfTree->addProperty(m_properties["DiffSphere"]); - hwhmRangeSelector->setVisible(false); - m_uiForm.ckPlotGuess->setChecked(false); - m_blnManager->setValue(m_properties["UseDeltaFunc"], false); - break; - case 4: - m_cfTree->addProperty(m_properties["DiffRotDiscreteCircle"]); - hwhmRangeSelector->setVisible(false); - m_uiForm.ckPlotGuess->setChecked(false); - m_blnManager->setValue(m_properties["UseDeltaFunc"], false); - break; + const size_t binIndexLow = + m_cfInputWS->binIndexOf(m_dblManager->value(m_properties["StartX"])); + const size_t binIndexHigh = + m_cfInputWS->binIndexOf(m_dblManager->value(m_properties["EndX"])); + const size_t nData = binIndexHigh - binIndexLow; + + std::vector<double> inputXData(nData); + const Mantid::MantidVec &XValues = m_cfInputWS->readX(0); + const bool isHistogram = m_cfInputWS->isHistogramData(); + + for (size_t i = 0; i < nData; i++) { + if (isHistogram) { + inputXData[i] = + 0.5 * (XValues[binIndexLow + i] + XValues[binIndexLow + i + 1]); + } else { + inputXData[i] = XValues[binIndexLow + i]; } - - // Disable Plot Guess and Use Delta Function for DiffSphere and DiffRotDiscreteCircle - m_uiForm.ckPlotGuess->setEnabled(index < 3); - m_properties["UseDeltaFunc"]->setEnabled(index < 3); - - updatePlotOptions(); } + FunctionDomain1DVector domain(inputXData); + FunctionValues outputData(domain); + function->function(domain, outputData); - void ConvFit::bgTypeSelection(int index) - { - if ( index == 2 ) - { - m_properties["LinearBackground"]->addSubProperty(m_properties["BGA1"]); - } - else - { - m_properties["LinearBackground"]->removeSubProperty(m_properties["BGA1"]); - } + QVector<double> dataX, dataY; + + for (size_t i = 0; i < nData; i++) { + dataX.append(inputXData[i]); + dataY.append(outputData.getCalculated(i)); } + IAlgorithm_sptr createWsAlg = + AlgorithmManager::Instance().create("CreateWorkspace"); + createWsAlg->initialize(); + createWsAlg->setChild(true); + createWsAlg->setLogging(false); + createWsAlg->setProperty("OutputWorkspace", "__GuessAnon"); + createWsAlg->setProperty("NSpec", 1); + createWsAlg->setProperty("DataX", dataX.toStdVector()); + createWsAlg->setProperty("DataY", dataY.toStdVector()); + createWsAlg->execute(); + MatrixWorkspace_sptr guessWs = createWsAlg->getProperty("OutputWorkspace"); + + m_uiForm.ppPlot->addSpectrum("Guess", guessWs, 0, Qt::green); +} - void ConvFit::updatePlot() - { - using Mantid::Kernel::Exception::NotFoundError; +/** + * Fits a single spectrum to the plot + */ +void ConvFit::singleFit() { + if (!validate()) + return; - if(!m_cfInputWS) - { - g_log.error("No workspace loaded, cannot create preview plot."); - return; - } + updatePlot(); - const bool plotGuess = m_uiForm.ckPlotGuess->isChecked(); - m_uiForm.ckPlotGuess->setChecked(false); + m_uiForm.ckPlotGuess->setChecked(false); - int specNo = m_uiForm.spPlotSpectrum->text().toInt(); + CompositeFunction_sptr function = + createFunction(m_uiForm.ckTieCentres->isChecked()); - m_uiForm.ppPlot->clear(); - m_uiForm.ppPlot->addSpectrum("Sample", m_cfInputWS, specNo); + // get output name + QString fitType = fitTypeString(); + QString bgType = backgroundString(); - try - { - const QPair<double, double> curveRange = m_uiForm.ppPlot->getCurveRange("Sample"); - const std::pair<double, double> range(curveRange.first, curveRange.second); - m_uiForm.ppPlot->getRangeSelector("ConvFitRange")->setRange(range.first, range.second); - m_uiForm.ckPlotGuess->setChecked(plotGuess); - } - catch(std::invalid_argument & exc) - { - showMessageBox(exc.what()); - } + if (fitType == "") { + g_log.error("No fit type defined."); + } - // Default FWHM to resolution of instrument - double resolution = getInstrumentResolution(m_cfInputWSName.toStdString()); - if(resolution > 0) - { - m_dblManager->setValue(m_properties["Lorentzian 1.FWHM"], resolution); - m_dblManager->setValue(m_properties["Lorentzian 2.FWHM"], resolution); - } + m_singleFitOutputName = + runPythonCode( + QString( + "from IndirectCommon import getWSprefix\nprint getWSprefix('") + + m_cfInputWSName + QString("')\n")) + .trimmed(); + m_singleFitOutputName += + QString("conv_") + fitType + bgType + m_uiForm.spPlotSpectrum->text(); + int maxIterations = + static_cast<int>(m_dblManager->value(m_properties["MaxIterations"])); + + m_singleFitAlg = AlgorithmManager::Instance().create("Fit"); + m_singleFitAlg->initialize(); + m_singleFitAlg->setPropertyValue("Function", function->asString()); + m_singleFitAlg->setPropertyValue("InputWorkspace", + m_cfInputWSName.toStdString()); + m_singleFitAlg->setProperty<int>("WorkspaceIndex", + m_uiForm.spPlotSpectrum->text().toInt()); + m_singleFitAlg->setProperty<double>( + "StartX", m_dblManager->value(m_properties["StartX"])); + m_singleFitAlg->setProperty<double>( + "EndX", m_dblManager->value(m_properties["EndX"])); + m_singleFitAlg->setProperty("Output", m_singleFitOutputName.toStdString()); + m_singleFitAlg->setProperty("CreateOutput", true); + m_singleFitAlg->setProperty("OutputCompositeMembers", true); + m_singleFitAlg->setProperty("ConvolveMembers", true); + m_singleFitAlg->setProperty("MaxIterations", maxIterations); + m_singleFitAlg->setProperty( + "Minimizer", minimizerString(m_singleFitOutputName).toStdString()); + + m_batchAlgoRunner->addAlgorithm(m_singleFitAlg); + connect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), this, + SLOT(singleFitComplete(bool))); + m_batchAlgoRunner->executeBatchAsync(); +} - // If there is a result plot then plot it - if(AnalysisDataService::Instance().doesExist(m_pythonExportWsName)) - { - WorkspaceGroup_sptr outputGroup = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(m_pythonExportWsName); - if(specNo >= static_cast<int>(outputGroup->size())) - return; - MatrixWorkspace_sptr ws = boost::dynamic_pointer_cast<MatrixWorkspace>(outputGroup->getItem(specNo)); - if(ws) - m_uiForm.ppPlot->addSpectrum("Fit", ws, 1, Qt::red); - } +/** + * Handle completion of the fit algorithm for single fit. + * + * @param error If the fit algorithm failed + */ +void ConvFit::singleFitComplete(bool error) { + disconnect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), this, + SLOT(singleFitComplete(bool))); + + if (error) { + showMessageBox("Fit algorithm failed."); + return; } + // Plot the line on the mini plot + m_uiForm.ppPlot->removeSpectrum("Guess"); + m_uiForm.ppPlot->addSpectrum("Fit", m_singleFitOutputName + "_Workspace", 1, + Qt::red); - void ConvFit::plotGuess() - { - m_uiForm.ppPlot->removeSpectrum("Guess"); - - // Do nothing if there is not a sample and resolution - if(!(m_uiForm.dsSampleInput->isValid() && m_uiForm.dsResInput->isValid() - && m_uiForm.ckPlotGuess->isChecked())) - return; + IFunction_sptr outputFunc = m_singleFitAlg->getProperty("Function"); - bool tieCentres = (m_uiForm.cbFitType->currentIndex() > 1); - CompositeFunction_sptr function = createFunction(tieCentres); + QString functionName = m_uiForm.cbFitType->currentText(); - if ( m_cfInputWS == NULL ) - { - updatePlot(); - } + // Get params. + QMap<QString, double> parameters; + std::vector<std::string> parNames = outputFunc->getParameterNames(); + std::vector<double> parVals; - const size_t binIndexLow = m_cfInputWS->binIndexOf(m_dblManager->value(m_properties["StartX"])); - const size_t binIndexHigh = m_cfInputWS->binIndexOf(m_dblManager->value(m_properties["EndX"])); - const size_t nData = binIndexHigh - binIndexLow; + QStringList params = getFunctionParameters(functionName); - std::vector<double> inputXData(nData); - const Mantid::MantidVec& XValues = m_cfInputWS->readX(0); - const bool isHistogram = m_cfInputWS->isHistogramData(); + for (size_t i = 0; i < parNames.size(); ++i) + parVals.push_back(outputFunc->getParameter(parNames[i])); - for ( size_t i = 0; i < nData; i++ ) - { - if ( isHistogram ) - { - inputXData[i] = 0.5 * ( XValues[binIndexLow+i] + XValues[binIndexLow+i+1] ); - } - else - { - inputXData[i] = XValues[binIndexLow+i]; - } - } + for (size_t i = 0; i < parNames.size(); ++i) + parameters[QString(parNames[i].c_str())] = parVals[i]; - FunctionDomain1DVector domain(inputXData); - FunctionValues outputData(domain); - function->function(domain, outputData); + // Populate Tree widget with values + // Background should always be f0 + m_dblManager->setValue(m_properties["BGA0"], parameters["f0.A0"]); + m_dblManager->setValue(m_properties["BGA1"], parameters["f0.A1"]); - QVector<double> dataX, dataY; + int fitTypeIndex = m_uiForm.cbFitType->currentIndex(); - for ( size_t i = 0; i < nData; i++ ) - { - dataX.append(inputXData[i]); - dataY.append(outputData.getCalculated(i)); - } + int funcIndex = 0; + int subIndex = 0; - IAlgorithm_sptr createWsAlg = AlgorithmManager::Instance().create("CreateWorkspace"); - createWsAlg->initialize(); - createWsAlg->setChild(true); - createWsAlg->setLogging(false); - createWsAlg->setProperty("OutputWorkspace", "__GuessAnon"); - createWsAlg->setProperty("NSpec", 1); - createWsAlg->setProperty("DataX", dataX.toStdVector()); - createWsAlg->setProperty("DataY", dataY.toStdVector()); - createWsAlg->execute(); - MatrixWorkspace_sptr guessWs = createWsAlg->getProperty("OutputWorkspace"); - - m_uiForm.ppPlot->addSpectrum("Guess", guessWs, 0, Qt::green); + // check if we're using a temperature correction + if (m_uiForm.ckTempCorrection->isChecked() && + !m_uiForm.leTempCorrection->text().isEmpty()) { + subIndex++; } + bool usingDeltaFunc = m_blnManager->value(m_properties["UseDeltaFunc"]); - void ConvFit::singleFit() - { - if(!validate()) - return; + // If using a delta function with any fit type or using two Lorentzians + bool usingCompositeFunc = + ((usingDeltaFunc && fitTypeIndex > 0) || fitTypeIndex == 2); - updatePlot(); + QString prefBase = "f1.f1."; - m_uiForm.ckPlotGuess->setChecked(false); + if (usingDeltaFunc) { + QString key = prefBase; + if (usingCompositeFunc) { + key += "f0."; + } - CompositeFunction_sptr function = createFunction(m_uiForm.ckTieCentres->isChecked()); + key += "Height"; - // get output name - QString fitType = fitTypeString(); - QString bgType = backgroundString(); + m_dblManager->setValue(m_properties["DeltaHeight"], parameters[key]); + funcIndex++; + } - if(fitType == "") - { - g_log.error("No fit type defined!"); - } + QString pref = prefBase; - m_singleFitOutputName = runPythonCode(QString("from IndirectCommon import getWSprefix\nprint getWSprefix('") + m_cfInputWSName + QString("')\n")).trimmed(); - m_singleFitOutputName += QString("conv_") + fitType + bgType + m_uiForm.spPlotSpectrum->text(); - int maxIterations = static_cast<int>(m_dblManager->value(m_properties["MaxIterations"])); - - m_singleFitAlg = AlgorithmManager::Instance().create("Fit"); - m_singleFitAlg->initialize(); - m_singleFitAlg->setPropertyValue("Function", function->asString()); - m_singleFitAlg->setPropertyValue("InputWorkspace", m_cfInputWSName.toStdString()); - m_singleFitAlg->setProperty<int>("WorkspaceIndex", m_uiForm.spPlotSpectrum->text().toInt()); - m_singleFitAlg->setProperty<double>("StartX", m_dblManager->value(m_properties["StartX"])); - m_singleFitAlg->setProperty<double>("EndX", m_dblManager->value(m_properties["EndX"])); - m_singleFitAlg->setProperty("Output", m_singleFitOutputName.toStdString()); - m_singleFitAlg->setProperty("CreateOutput", true); - m_singleFitAlg->setProperty("OutputCompositeMembers", true); - m_singleFitAlg->setProperty("ConvolveMembers", true); - m_singleFitAlg->setProperty("MaxIterations", maxIterations); - m_singleFitAlg->setProperty("Minimizer", minimizerString(m_singleFitOutputName).toStdString()); - - m_batchAlgoRunner->addAlgorithm(m_singleFitAlg); - connect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), - this, SLOT(singleFitComplete(bool))); - m_batchAlgoRunner->executeBatchAsync(); + if (usingCompositeFunc) { + pref += "f" + QString::number(funcIndex) + ".f" + + QString::number(subIndex) + "."; + } else { + pref += "f" + QString::number(subIndex) + "."; } + if (fitTypeIndex == 1 || fitTypeIndex == 2) { + functionName = "Lorentzian 1"; + } - /** - * Handle completion of the fit algorithm for single fit. - * - * @param error If the fit algorithm failed - */ - void ConvFit::singleFitComplete(bool error) - { - disconnect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), - this, SLOT(singleFitComplete(bool))); - - if(error) - { - showMessageBox("Fit algorithm failed."); - return; + if (fitTypeIndex == 2) { + for (auto it = params.begin(); it != params.end() - 3; ++it) { + QString functionParam = functionName + "." + *it; + QString paramValue = pref + *it; + m_dblManager->setValue(m_properties[functionParam], + parameters[paramValue]); } - // Plot the line on the mini plot - m_uiForm.ppPlot->removeSpectrum("Guess"); - m_uiForm.ppPlot->addSpectrum("Fit", m_singleFitOutputName+"_Workspace", 1, Qt::red); - - IFunction_sptr outputFunc = m_singleFitAlg->getProperty("Function"); - - // Get params. - QMap<QString,double> parameters; - std::vector<std::string> parNames = outputFunc->getParameterNames(); - std::vector<double> parVals; - - for( size_t i = 0; i < parNames.size(); ++i ) - parVals.push_back(outputFunc->getParameter(parNames[i])); - - for ( size_t i = 0; i < parNames.size(); ++i ) - parameters[QString(parNames[i].c_str())] = parVals[i]; + pref = prefBase; + pref += "f" + QString::number(funcIndex) + ".f" + + QString::number(subIndex) + "."; - // Populate Tree widget with values - // Background should always be f0 - m_dblManager->setValue(m_properties["BGA0"], parameters["f0.A0"]); - m_dblManager->setValue(m_properties["BGA1"], parameters["f0.A1"]); + functionName = "Lorentzian 2"; - int fitTypeIndex = m_uiForm.cbFitType->currentIndex(); - - int funcIndex = 0; - int subIndex = 0; + for (auto it = params.begin() + 3; it != params.end(); ++it) { + QString functionParam = functionName + "." + *it; + QString paramValue = pref + *it; + m_dblManager->setValue(m_properties[functionParam], + parameters[paramValue]); + } - //check if we're using a temperature correction - if (m_uiForm.ckTempCorrection->isChecked() && - !m_uiForm.leTempCorrection->text().isEmpty()) - { - subIndex++; + } else { + for (auto it = params.begin(); it != params.end(); ++it) { + QString functionParam = functionName + "." + *it; + QString paramValue = pref + *it; + m_dblManager->setValue(m_properties[functionParam], + parameters[paramValue]); } + } + funcIndex++; - bool usingDeltaFunc = m_blnManager->value(m_properties["UseDeltaFunc"]); + m_pythonExportWsName = ""; +} - // If using a delta function with any fit type or using two Lorentzians - bool usingCompositeFunc = ((usingDeltaFunc && fitTypeIndex > 0) || fitTypeIndex == 2); +/** + * Handles the user entering a new minimum spectrum index. + * + * Prevents the user entering an overlapping spectra range. + * + * @param value Minimum spectrum index + */ +void ConvFit::specMinChanged(int value) { + m_uiForm.spSpectraMax->setMinimum(value); +} - QString prefBase = "f1.f1."; +/** + * Handles the user entering a new maximum spectrum index. + * + * Prevents the user entering an overlapping spectra range. + * + * @param value Maximum spectrum index + */ +void ConvFit::specMaxChanged(int value) { + m_uiForm.spSpectraMin->setMaximum(value); +} - if ( usingDeltaFunc ) - { - QString key = prefBase; - if (usingCompositeFunc) - { - key += "f0."; - } +void ConvFit::minChanged(double val) { + m_dblManager->setValue(m_properties["StartX"], val); +} - key += "Height"; +void ConvFit::maxChanged(double val) { + m_dblManager->setValue(m_properties["EndX"], val); +} - m_dblManager->setValue(m_properties["DeltaHeight"], parameters[key]); - funcIndex++; - } +void ConvFit::hwhmChanged(double val) { + const double peakCentre = + m_dblManager->value(m_properties["Lorentzian 1.PeakCentre"]); + // Always want FWHM to display as positive. + const double hwhm = std::fabs(val - peakCentre); + // Update the property + auto hwhmRangeSelector = m_uiForm.ppPlot->getRangeSelector("ConvFitHWHM"); + hwhmRangeSelector->blockSignals(true); + m_dblManager->setValue(m_properties["Lorentzian 1.FWHM"], hwhm * 2); + hwhmRangeSelector->blockSignals(false); +} - if ( fitTypeIndex == 1 || fitTypeIndex == 2 ) - { - // One Lorentz - QString pref = prefBase; +void ConvFit::backgLevel(double val) { + m_dblManager->setValue(m_properties["BGA0"], val); +} - if ( usingCompositeFunc ) - { - pref += "f" + QString::number(funcIndex) + ".f" + QString::number(subIndex) + "."; - } - else - { - pref += "f" + QString::number(subIndex) + "."; - } +void ConvFit::updateRS(QtProperty *prop, double val) { + auto fitRangeSelector = m_uiForm.ppPlot->getRangeSelector("ConvFitRange"); + auto backRangeSelector = + m_uiForm.ppPlot->getRangeSelector("ConvFitBackRange"); + + if (prop == m_properties["StartX"]) { + fitRangeSelector->setMinimum(val); + } else if (prop == m_properties["EndX"]) { + fitRangeSelector->setMaximum(val); + } else if (prop == m_properties["BGA0"]) { + backRangeSelector->setMinimum(val); + } else if (prop == m_properties["Lorentzian 1.FWHM"]) { + hwhmUpdateRS(val); + } else if (prop == m_properties["Lorentzian 1.PeakCentre"]) { + hwhmUpdateRS(m_dblManager->value(m_properties["Lorentzian 1.FWHM"])); + } +} - m_dblManager->setValue(m_properties["Lorentzian 1.Amplitude"], parameters[pref+"Amplitude"]); - m_dblManager->setValue(m_properties["Lorentzian 1.PeakCentre"], parameters[pref+"PeakCentre"]); - m_dblManager->setValue(m_properties["Lorentzian 1.FWHM"], parameters[pref+"FWHM"]); - funcIndex++; - } +void ConvFit::hwhmUpdateRS(double val) { + const double peakCentre = + m_dblManager->value(m_properties["Lorentzian 1.PeakCentre"]); + auto hwhmRangeSelector = m_uiForm.ppPlot->getRangeSelector("ConvFitHWHM"); + hwhmRangeSelector->setMinimum(peakCentre - val / 2); + hwhmRangeSelector->setMaximum(peakCentre + val / 2); +} - if ( fitTypeIndex == 2 ) - { - // Two Lorentz - QString pref = prefBase; - pref += "f" + QString::number(funcIndex) + ".f" + QString::number(subIndex) + "."; +void ConvFit::checkBoxUpdate(QtProperty *prop, bool checked) { + UNUSED_ARG(checked); - m_dblManager->setValue(m_properties["Lorentzian 2.Amplitude"], parameters[pref+"Amplitude"]); - m_dblManager->setValue(m_properties["Lorentzian 2.PeakCentre"], parameters[pref+"PeakCentre"]); - m_dblManager->setValue(m_properties["Lorentzian 2.FWHM"], parameters[pref+"FWHM"]); + if (prop == m_properties["UseDeltaFunc"]) + updatePlotOptions(); + else if (prop == m_properties["UseFABADA"]) { + if (checked) { + // FABADA needs a much higher iteration limit + m_dblManager->setValue(m_properties["MaxIterations"], 20000); + + m_properties["FABADA"]->addSubProperty(m_properties["OutputFABADAChain"]); + m_properties["FABADA"]->addSubProperty(m_properties["FABADAChainLength"]); + m_properties["FABADA"]->addSubProperty( + m_properties["FABADAConvergenceCriteria"]); + m_properties["FABADA"]->addSubProperty( + m_properties["FABADAJumpAcceptanceRate"]); + } else { + m_dblManager->setValue(m_properties["MaxIterations"], 500); + + m_properties["FABADA"]->removeSubProperty( + m_properties["OutputFABADAChain"]); + m_properties["FABADA"]->removeSubProperty( + m_properties["FABADAChainLength"]); + m_properties["FABADA"]->removeSubProperty( + m_properties["FABADAConvergenceCriteria"]); + m_properties["FABADA"]->removeSubProperty( + m_properties["FABADAJumpAcceptanceRate"]); } + } +} - if ( fitTypeIndex == 3 ) - { - // DiffSphere - QString pref = prefBase; - - if ( usingCompositeFunc ) - { - pref += "f" + QString::number(funcIndex) + ".f" + QString::number(subIndex) + "."; - } - else - { - pref += "f" + QString::number(subIndex) + "."; - } - - m_dblManager->setValue(m_properties["Diffusion Sphere.Intensity"], parameters[pref+"Intensity"]); - m_dblManager->setValue(m_properties["Diffusion Sphere.Radius"], parameters[pref+"Radius"]); - m_dblManager->setValue(m_properties["Diffusion Sphere.Diffusion"], parameters[pref+"Diffusion"]); - m_dblManager->setValue(m_properties["Diffusion Sphere.Shift"], parameters[pref+"Shift"]); - } +void ConvFit::fitContextMenu(const QPoint &) { + QtBrowserItem *item(NULL); - if ( fitTypeIndex == 4 ) - { - // DiffSphere - QString pref = prefBase; + item = m_cfTree->currentItem(); - if ( usingCompositeFunc ) - { - pref += "f" + QString::number(funcIndex) + ".f" + QString::number(subIndex) + "."; - } - else - { - pref += "f" + QString::number(subIndex) + "."; - } + if (!item) + return; - m_dblManager->setValue(m_properties["Diffusion Circle.Intensity"], parameters[pref+"Intensity"]); - m_dblManager->setValue(m_properties["Diffusion Circle.Radius"], parameters[pref+"Radius"]); - m_dblManager->setValue(m_properties["Diffusion Circle.Decay"], parameters[pref+"Decay"]); - m_dblManager->setValue(m_properties["Diffusion Circle.Shift"], parameters[pref+"Shift"]); - } + // is it a fit property ? + QtProperty *prop = item->property(); + if (prop == m_properties["StartX"] || prop == m_properties["EndX"]) + return; - m_pythonExportWsName = ""; - } + // is it already fixed? + bool fixed = prop->propertyManager() != m_dblManager; + if (fixed && prop->propertyManager() != m_stringManager) + return; + // Create the menu + QMenu *menu = new QMenu("ConvFit", m_cfTree); + QAction *action; - /** - * Handles the user entering a new minimum spectrum index. - * - * Prevents the user entering an overlapping spectra range. - * - * @param value Minimum spectrum index - */ - void ConvFit::specMinChanged(int value) - { - m_uiForm.spSpectraMax->setMinimum(value); + if (!fixed) { + action = new QAction("Fix", m_parentWidget); + connect(action, SIGNAL(triggered()), this, SLOT(fixItem())); + } else { + action = new QAction("Remove Fix", m_parentWidget); + connect(action, SIGNAL(triggered()), this, SLOT(unFixItem())); } + menu->addAction(action); - /** - * Handles the user entering a new maximum spectrum index. - * - * Prevents the user entering an overlapping spectra range. - * - * @param value Maximum spectrum index - */ - void ConvFit::specMaxChanged(int value) - { - m_uiForm.spSpectraMin->setMaximum(value); - } - + // Show the menu + menu->popup(QCursor::pos()); +} - void ConvFit::minChanged(double val) - { - m_dblManager->setValue(m_properties["StartX"], val); - } +void ConvFit::fixItem() { + QtBrowserItem *item = m_cfTree->currentItem(); + // Determine what the property is. + QtProperty *prop = item->property(); + QtProperty *fixedProp = m_stringManager->addProperty(prop->propertyName()); + QtProperty *fprlbl = m_stringManager->addProperty("Fixed"); + fixedProp->addSubProperty(fprlbl); + m_stringManager->setValue(fixedProp, prop->valueText()); - void ConvFit::maxChanged(double val) - { - m_dblManager->setValue(m_properties["EndX"], val); - } + item->parent()->property()->addSubProperty(fixedProp); + m_fixedProps[fixedProp] = prop; - void ConvFit::hwhmChanged(double val) - { - const double peakCentre = m_dblManager->value(m_properties["Lorentzian 1.PeakCentre"]); - // Always want FWHM to display as positive. - const double hwhm = std::fabs(val-peakCentre); - // Update the property - auto hwhmRangeSelector = m_uiForm.ppPlot->getRangeSelector("ConvFitHWHM"); - hwhmRangeSelector->blockSignals(true); - m_dblManager->setValue(m_properties["Lorentzian 1.FWHM"], hwhm*2); - hwhmRangeSelector->blockSignals(false); - } + item->parent()->property()->removeSubProperty(prop); +} +void ConvFit::unFixItem() { + QtBrowserItem *item = m_cfTree->currentItem(); - void ConvFit::backgLevel(double val) - { - m_dblManager->setValue(m_properties["BGA0"], val); + QtProperty *prop = item->property(); + if (prop->subProperties().empty()) { + item = item->parent(); + prop = item->property(); } + item->parent()->property()->addSubProperty(m_fixedProps[prop]); + item->parent()->property()->removeSubProperty(prop); + m_fixedProps.remove(prop); + QtProperty *proplbl = prop->subProperties()[0]; + delete proplbl; + delete prop; +} - void ConvFit::updateRS(QtProperty* prop, double val) - { - auto fitRangeSelector = m_uiForm.ppPlot->getRangeSelector("ConvFitRange"); - auto backRangeSelector = m_uiForm.ppPlot->getRangeSelector("ConvFitBackRange"); +void ConvFit::showTieCheckbox(QString fitType) { + m_uiForm.ckTieCentres->setVisible(fitType == "Two Lorentzians"); +} - if ( prop == m_properties["StartX"] ) { fitRangeSelector->setMinimum(val); } - else if ( prop == m_properties["EndX"] ) { fitRangeSelector->setMaximum(val); } - else if ( prop == m_properties["BGA0"] ) { backRangeSelector->setMinimum(val); } - else if ( prop == m_properties["Lorentzian 1.FWHM"] ) { hwhmUpdateRS(val); } - else if ( prop == m_properties["Lorentzian 1.PeakCentre"] ) - { - hwhmUpdateRS(m_dblManager->value(m_properties["Lorentzian 1.FWHM"])); +/** + * Gets a list of parameters for a given fit function. + * @return List fo parameters + */ +QStringList ConvFit::getFunctionParameters(QString functionName) { + QStringList parameters; + if (functionName.compare("Two Lorentzians") == 0) { + functionName = "Lorentzian"; + IFunction_sptr func = + FunctionFactory::Instance().createFunction(functionName.toStdString()); + + for (size_t i = 0; i < func->nParams(); i++) { + parameters << QString::fromStdString(func->parameterName(i)); } } - - void ConvFit::hwhmUpdateRS(double val) - { - const double peakCentre = m_dblManager->value(m_properties["Lorentzian 1.PeakCentre"]); - auto hwhmRangeSelector = m_uiForm.ppPlot->getRangeSelector("ConvFitHWHM"); - hwhmRangeSelector->setMinimum(peakCentre-val/2); - hwhmRangeSelector->setMaximum(peakCentre+val/2); + if (functionName.compare("One Lorentzian") == 0) { + functionName = "Lorentzian"; } + if (functionName.compare("Zero Lorentzians") == 0) { + parameters.append("Zero"); + } else { + IFunction_sptr func = + FunctionFactory::Instance().createFunction(functionName.toStdString()); - void ConvFit::checkBoxUpdate(QtProperty* prop, bool checked) - { - UNUSED_ARG(checked); - - if(prop == m_properties["UseDeltaFunc"]) - updatePlotOptions(); - else if(prop == m_properties["UseFABADA"]) - { - if(checked) - { - // FABADA needs a much higher iteration limit - m_dblManager->setValue(m_properties["MaxIterations"], 20000); - - m_properties["FABADA"]->addSubProperty(m_properties["OutputFABADAChain"]); - m_properties["FABADA"]->addSubProperty(m_properties["FABADAChainLength"]); - m_properties["FABADA"]->addSubProperty(m_properties["FABADAConvergenceCriteria"]); - m_properties["FABADA"]->addSubProperty(m_properties["FABADAJumpAcceptanceRate"]); - } - else - { - m_dblManager->setValue(m_properties["MaxIterations"], 500); - - m_properties["FABADA"]->removeSubProperty(m_properties["OutputFABADAChain"]); - m_properties["FABADA"]->removeSubProperty(m_properties["FABADAChainLength"]); - m_properties["FABADA"]->removeSubProperty(m_properties["FABADAConvergenceCriteria"]); - m_properties["FABADA"]->removeSubProperty(m_properties["FABADAJumpAcceptanceRate"]); - } + for (size_t i = 0; i < func->nParams(); i++) { + parameters << QString::fromStdString(func->parameterName(i)); } } + return parameters; +} - void ConvFit::fitContextMenu(const QPoint &) - { - QtBrowserItem* item(NULL); - - item = m_cfTree->currentItem(); - - if ( ! item ) - return; - - // is it a fit property ? - QtProperty* prop = item->property(); - - if ( prop == m_properties["StartX"] || prop == m_properties["EndX"] ) - return; +/** + * Handles a new fit function being selected. + * @param functionName Name of new fit function + */ +void ConvFit::fitFunctionSelected(const QString &functionName) { + // remove previous parameters from tree + m_cfTree->removeProperty(m_properties["FitFunction1"]); + m_cfTree->removeProperty(m_properties["FitFunction2"]); + + m_uiForm.ckPlotGuess->setChecked(false); + m_uiForm.ckTieCentres->setChecked(false); + + // Add new parameter elements + int fitFunctionIndex = m_uiForm.cbFitType->currentIndex(); + QStringList parameters = getFunctionParameters(functionName); + updatePlotOptions(); + + // Two Loremtzians Fit + if (fitFunctionIndex == 2) { + m_properties["FitFunction1"] = m_grpManager->addProperty("Lorentzian 1"); + m_cfTree->addProperty(m_properties["FitFunction1"]); + m_properties["FitFunction2"] = m_grpManager->addProperty("Lorentzian 2"); + m_cfTree->addProperty(m_properties["FitFunction2"]); + } else { + m_properties["FitFunction1"] = m_grpManager->addProperty(functionName); + m_cfTree->addProperty(m_properties["FitFunction1"]); + } - // is it already fixed? - bool fixed = prop->propertyManager() != m_dblManager; + QString propName; + // No fit function parameters required for Zero + if (parameters[0].compare("Zero") != 0) { + // Two Lorentzians Fit + if (fitFunctionIndex == 2) { + int count = 0; + propName = "Lorentzian 1"; + for (auto it = parameters.begin(); it != parameters.end(); ++it) { + if (count == 3) { + propName = "Lorentzian 2"; + } + QString name = propName + "." + *it; + m_properties[name] = m_dblManager->addProperty(*it); - if ( fixed && prop->propertyManager() != m_stringManager ) - return; + if (QString(*it).compare("FWHM") == 0) { + m_dblManager->setValue(m_properties[name], 0.0175); + } else { + m_dblManager->setValue(m_properties[name], 0.0); + } + if (QString(*it).compare("Amplitude") == 0 || + QString(*it).compare("Intensity") == 0) { + m_dblManager->setValue(m_properties[name], 1.0); + } - // Create the menu - QMenu* menu = new QMenu("ConvFit", m_cfTree); - QAction* action; + m_dblManager->setDecimals(m_properties[name], NUM_DECIMALS); + if (count < 3) { + m_properties["FitFunction1"]->addSubProperty(m_properties[name]); + } else { + m_properties["FitFunction2"]->addSubProperty(m_properties[name]); + } + count++; + } + } else { + if (fitFunctionIndex == 1) { + propName = "Lorentzian 1"; + } else { + propName = functionName; + } + for (auto it = parameters.begin(); it != parameters.end(); ++it) { + QString name = propName + "." + *it; + m_properties[name] = m_dblManager->addProperty(*it); + + if (QString(*it).compare("FWHM") == 0) { + m_dblManager->setValue(m_properties[name], 0.0175); + } else { + m_dblManager->setValue(m_properties[name], 0.0); + } + if (QString(*it).compare("Amplitude") == 0 || + QString(*it).compare("Intensity") == 0) { + m_dblManager->setValue(m_properties[name], 1.0); + } - if ( ! fixed ) - { - action = new QAction("Fix", m_parentWidget); - connect(action, SIGNAL(triggered()), this, SLOT(fixItem())); - } - else - { - action = new QAction("Remove Fix", m_parentWidget); - connect(action, SIGNAL(triggered()), this, SLOT(unFixItem())); + m_dblManager->setDecimals(m_properties[name], NUM_DECIMALS); + m_properties["FitFunction1"]->addSubProperty(m_properties[name]); + } } - - menu->addAction(action); - - // Show the menu - menu->popup(QCursor::pos()); } +} +/** + * Populates the plot combobox + */ +void ConvFit::updatePlotOptions() { + m_uiForm.cbPlotType->clear(); - void ConvFit::fixItem() - { - QtBrowserItem* item = m_cfTree->currentItem(); - - // Determine what the property is. - QtProperty* prop = item->property(); - QtProperty* fixedProp = m_stringManager->addProperty( prop->propertyName() ); - QtProperty* fprlbl = m_stringManager->addProperty("Fixed"); - fixedProp->addSubProperty(fprlbl); - m_stringManager->setValue(fixedProp, prop->valueText()); - - item->parent()->property()->addSubProperty(fixedProp); - - m_fixedProps[fixedProp] = prop; + const bool deltaFunction = m_blnManager->value(m_properties["UseDeltaFunc"]); + const int fitFunctionType = m_uiForm.cbFitType->currentIndex(); + QStringList plotOptions; + plotOptions << "None"; - item->parent()->property()->removeSubProperty(prop); + if (deltaFunction && fitFunctionType < 3){ + plotOptions << "Height"; } - - - void ConvFit::unFixItem() - { - QtBrowserItem* item = m_cfTree->currentItem(); - - QtProperty* prop = item->property(); - if ( prop->subProperties().empty() ) - { - item = item->parent(); - prop = item->property(); - } - - item->parent()->property()->addSubProperty(m_fixedProps[prop]); - item->parent()->property()->removeSubProperty(prop); - m_fixedProps.remove(prop); - QtProperty* proplbl = prop->subProperties()[0]; - delete proplbl; - delete prop; + + QStringList params = QStringList(); + + if (fitFunctionType != 2) { + params = getFunctionParameters(m_uiForm.cbFitType->currentText()); + } else { + params = getFunctionParameters(QString("One Lorentzian")); } - - - void ConvFit::showTieCheckbox(QString fitType) - { - m_uiForm.ckTieCentres->setVisible( fitType == "Two Lorentzians" ); + if (fitFunctionType != 0) { + plotOptions.append(params); } - - void ConvFit::updatePlotOptions() - { - m_uiForm.cbPlotType->clear(); - - bool deltaFunction = m_blnManager->value(m_properties["UseDeltaFunc"]); - - QStringList plotOptions; - plotOptions << "None"; - - if(deltaFunction) - plotOptions << "Height"; - - switch(m_uiForm.cbFitType->currentIndex()) - { - // Lorentzians - case 1: - case 2: - plotOptions << "Amplitude" << "FWHM"; - if(deltaFunction) - plotOptions << "EISF"; - break; - - // DiffSphere - case 3: - plotOptions << "Intensity" << "Radius" << "Diffusion" << "Shift"; - break; - - // DiffRotDiscreteCircle - case 4: - plotOptions << "Intensity" << "Radius" << "Decay" << "Shift"; - break; - - default: - break; - } - - plotOptions << "All"; - m_uiForm.cbPlotType->addItems(plotOptions); + if(fitFunctionType != 0 || deltaFunction){ + plotOptions << "All"; } + m_uiForm.cbPlotType->addItems(plotOptions); +} } // namespace IDA } // namespace CustomInterfaces -} // namespace MantidQt +} // namespace MantidQt \ No newline at end of file diff --git a/Code/Mantid/docs/source/interfaces/Indirect_DataAnalysis.rst b/Code/Mantid/docs/source/interfaces/Indirect_DataAnalysis.rst index 3647dbbea9283837f3898ba9c82f3078151cc025..ba2dae8c3817fa66b7b26255f48ace70413e3f26 100644 --- a/Code/Mantid/docs/source/interfaces/Indirect_DataAnalysis.rst +++ b/Code/Mantid/docs/source/interfaces/Indirect_DataAnalysis.rst @@ -341,33 +341,47 @@ and *Use Delta Function* options in the interface. - DeltaFunction - - :ref:`ProductFunction <func-ProductFunction>` + - :ref:`ProductFunction <func-ProductFunction>` (One Lorentzian) - :ref:`Lorentzian <func-Lorentzian>` - Temperature Correction - - :ref:`ProductFunction <func-ProductFunction>` + - :ref:`ProductFunction <func-ProductFunction>` (Two Lorentzians) - :ref:`Lorentzian <func-Lorentzian>` - Temperature Correction - - :ref:`ProductFunction <func-ProductFunction>` + - :ref:`ProductFunction <func-ProductFunction>` (InelasticDiffSphere) - - :ref:`DiffSphere <func-DiffSphere>` + - :ref:`Inelastic Diff Sphere <func-DiffSphere>` - Temperature Correction - - :ref:`ProductFunction <func-ProductFunction>` + - :ref:`ProductFunction <func-ProductFunction>` (InelasticDiffRotDiscreteCircle) - - :ref:`DiffRotDiscreteCircle <func-DiffRotDiscreteCircle>` + - :ref:`Inelastic Diff Rot Discrete Circle <func-DiffRotDiscreteCircle>` - Temperature Correction + + - :ref:`ProductFunction <func-ProductFunction>` (ElasticDiffSphere) -Note that it is the Inelastic variants of :ref:`DiffSphere <func-DiffSphere>` -and :ref:`DiffRotDiscreteCircle <func-DiffRotDiscreteCircle>` that are used in -this interface. + - :ref:`Elastic Diff Sphere <func-DiffSphere>` + + - Temperature Correction + + - :ref:`ProductFunction <func-ProductFunction>` (ElasticDiffRotDiscreteCircle) + + - :ref:`Elastic Diff Rot Discrete Circle <func-DiffRotDiscreteCircle>` + + - Temperature Correction + + - :ref:`ProductFunction <func-ProductFunction>` (StretchedExpFT) + + - :ref:`StretchedExpFT <func-StretchedExpFT>` + + - Temperature Correction The Temperature Correction is a :ref:`UserFunction <func-UserFunction>` with the formula :math:`((x * 11.606) / T) / (1 - exp(-((x * 11.606) / T)))` where diff --git a/Code/Mantid/scripts/Inelastic/IndirectDataAnalysis.py b/Code/Mantid/scripts/Inelastic/IndirectDataAnalysis.py index 4e76318213db1e49c51a742b6510c4ae245754a8..b3d509f99632d2d3992e173394ccc6e91568ba15 100644 --- a/Code/Mantid/scripts/Inelastic/IndirectDataAnalysis.py +++ b/Code/Mantid/scripts/Inelastic/IndirectDataAnalysis.py @@ -81,7 +81,7 @@ def confitSeq(inputWS, func, startX, endX, ftype, bgd, for i in xrange(specMin, specMax+1)] fit_args = dict() - if 'DS' in ftype or 'DC' in ftype: + if 'DS' in ftype or 'DC' in ftype or 'SFT' in ftype: fit_args['PassWSIndexToFunction'] = True PlotPeakByLogValue(Input=';'.join(input_params), @@ -107,6 +107,8 @@ def confitSeq(inputWS, func, startX, endX, ftype, bgd, parameter_names = ['Height', 'Intensity', 'Radius', 'Diffusion', 'Shift'] elif 'DC' in ftype: parameter_names = ['Height', 'Intensity', 'Radius', 'Decay', 'Shift'] + elif 'SFT' in ftype: + parameter_names = ['height', 'tau', 'beta'] else: parameter_names = ['Height', 'Amplitude', 'FWHM', 'EISF']