Newer
Older
#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 <QFileInfo>
#include <QMenu>
#include <qwt_plot.h>
#include <qwt_plot_curve.h>
namespace
{
Mantid::Kernel::Logger g_log("ConvFit");
}
namespace MantidQt
{
namespace CustomInterfaces
{
namespace IDA
{
ConvFit::ConvFit(QWidget * parent) :
m_stringManager(NULL), m_cfTree(NULL),
m_fixedProps(),
m_cfInputWS(), m_cfInputWSName(),
m_confitResFileType()
void ConvFit::setup()
{
// Create Property Managers
m_stringManager = new QtStringPropertyManager();
// Create TreeProperty Widget
m_cfTree = new QtTreePropertyBrowser();
// 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
m_properties["Convolve"] = m_blnManager->addProperty("Convolve");
m_cfTree->addProperty(m_properties["Convolve"]);
m_blnManager->setValue(m_properties["Convolve"], true);
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"]);
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"]);
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));
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.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 &)));
connect(m_uiForm.cbFitType,SIGNAL(currentIndexChanged(QString)),SLOT(showTieCheckbox(QString)));
showTieCheckbox( m_uiForm.cbFitType->currentText() );
}
void ConvFit::run()
{
QString fitType = fitTypeString();
QString bgType = backgroundString();
{
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();
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"
"specMin = " + specMin + "\n"
"specMax = " + specMax + "\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());
pyInput += "temp=" + temperature + "\n";
"bg = '" + bgType + "'\n"
"ftype = '" + fitType + "'\n"
"confitSeq(input, func, startx, endx, ftype, bg, temp, specMin, specMax, convolve, Plot=plot, Save=save)\n";
QString pyOutput = runPythonCode(pyInput);
// Set the result workspace for Python script export
QString inputWsName = QString::fromStdString(m_cfInputWS->getName());
QString resultWsName = inputWsName.left(inputWsName.lastIndexOf("_")) + "_conv_" + fitType + bgType + specMin + "_to_" + specMax + "_Workspaces";
m_pythonExportWsName = resultWsName.toStdString();
}
/**
* Validates the user's inputs in the ConvFit tab.
*/
UserInputValidator uiv;
uiv.checkDataSelectorIsValid("Sample", m_uiForm.dsSampleInput);
uiv.checkDataSelectorIsValid("Resolution", m_uiForm.dsResInput);
auto range = std::make_pair(m_dblManager->value(m_properties["StartX"]), m_dblManager->value(m_properties["EndX"]));
uiv.checkValidRange("Fitting Range", range);
// 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.");
QString error = uiv.generateErrorMessage();
showMessageBox(error);
return error.isEmpty();
}
void ConvFit::loadSettings(const QSettings & settings)
{
m_uiForm.dsSampleInput->readSettings(settings.group());
m_uiForm.dsResInput->readSettings(settings.group());
/**
* 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_cfInputWS = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(m_cfInputWSName.toStdString());
int maxSpecIndex = static_cast<int>(m_cfInputWS->getNumberHistograms()) - 1;
m_uiForm.spPlotSpectrum->setMaximum(maxSpecIndex);
m_uiForm.spPlotSpectrum->setMinimum(0);
m_uiForm.spPlotSpectrum->setValue(0);
m_uiForm.spSpectraMin->setMaximum(maxSpecIndex);
m_uiForm.spSpectraMin->setMinimum(0);
m_uiForm.spSpectraMax->setMaximum(maxSpecIndex);
m_uiForm.spSpectraMax->setMinimum(0);
m_uiForm.spSpectraMax->setValue(maxSpecIndex);
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
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
* (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)
* +-- Temperature Correction (yes/no)
* +-- ProductFunction
* |
* +-- 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 );
size_t index = 0;
// -------------------------------------
// --- Composite / Linear Background ---
// -------------------------------------
func = FunctionFactory::Instance().createFunction("LinearBackground");
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() );
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()); }
}
// --------------------------------------------
// --- Composite / Convolution / Resolution ---
// --------------------------------------------
func = FunctionFactory::Instance().createFunction("Resolution");
//add resolution file
std::string resWorkspace = m_uiForm.dsResInput->getCurrentDataName().toStdString();
IFunction::Attribute attr(resWorkspace);
func->setAttribute("Workspace", attr);
// --------------------------------------------------------
// --- Composite / Convolution / Model / Delta Function ---
// --------------------------------------------------------
CompositeFunction_sptr model( new CompositeFunction );
bool useDeltaFunc = m_blnManager->value(m_properties["UseDeltaFunc"]);
size_t subIndex = 0;
func = FunctionFactory::Instance().createFunction("DeltaFunction");
index = model->addFunction(func);
std::string parName = createParName(index);
populateFunction(func, model, m_properties["DeltaFunction"], parName, false);
// ------------------------------------------------------------
// --- 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();
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"));
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);
// 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"));
createTemperatureCorrection(product);
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);
// -------------------------------------------------------------
// --- 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);
}
// ------------------------------------------------------------------------
// --- Composite / Convolution / Model / InelasticDiffRotDiscreteCircle ---
// ------------------------------------------------------------------------
if(fitTypeIndex == 4)
{
auto product = boost::dynamic_pointer_cast<CompositeFunction>(FunctionFactory::Instance().createFunction("ProductFunction"));
if(useTempCorrection)
{
createTemperatureCorrection(product);
}
func = FunctionFactory::Instance().createFunction("InelasticDiffRotDiscreteCircle");
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);
}
comp->applyTies();
return comp;
}
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;
double resolution = 0.0;
try
{
Mantid::Geometry::Instrument_const_sptr inst =
AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(workspaceName)->getInstrument();
std::string analyser = inst->getStringParameter("analyser")[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];
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.error("Could not load parameter file, ensure instrument directory is in data search paths.");
return 0.0;
}
inst = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(workspaceName)->getInstrument();
}
resolution = inst->getComponentByName(analyser)->getNumberParameter("resolution")[0];
}
catch(Mantid::Kernel::Exception::NotFoundError &e)
{
g_log.error("Could not load instrument resolution from parameter file");
resolution = 0.0;
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");
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);
lorentzGroup->addSubProperty(m_properties[name+".Amplitude"]);
lorentzGroup->addSubProperty(m_properties[name+".PeakCentre"]);
lorentzGroup->addSubProperty(m_properties[name+".FWHM"]);
return lorentzGroup;
}
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);
diffSphereGroup->addSubProperty(m_properties[name+".Intensity"]);
diffSphereGroup->addSubProperty(m_properties[name+".Radius"]);
diffSphereGroup->addSubProperty(m_properties[name+".Diffusion"]);
diffSphereGroup->addSubProperty(m_properties[name+".Shift"]);
QtProperty* ConvFit::createDiffRotDiscreteCircle(const QString & name)
{
QtProperty* diffRotDiscreteCircleGroup = m_grpManager->addProperty(name);
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");
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);
diffRotDiscreteCircleGroup->addSubProperty(m_properties[name+".Intensity"]);
diffRotDiscreteCircleGroup->addSubProperty(m_properties[name+".Radius"]);
diffRotDiscreteCircleGroup->addSubProperty(m_properties[name+".Decay"]);
diffRotDiscreteCircleGroup->addSubProperty(m_properties[name+".Shift"]);
return diffRotDiscreteCircleGroup;
}
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();
}
else
{
std::string propName = props[i]->propertyName().toStdString();
double propValue = props[i]->valueText().toDouble();
if ( propValue )
{
func->setParameter(propName, propValue);
}
/**
* 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";
case 0:
break;
case 1:
fitType += "1L"; break;
case 2:
fitType += "2L"; break;
}
return fitType;
}
/**
* 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 "";
}
}
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 )
{
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);
case 3:
m_cfTree->addProperty(m_properties["DiffSphere"]);
hwhmRangeSelector->setVisible(false);
m_blnManager->setValue(m_properties["UseDeltaFunc"], false);
case 4:
m_cfTree->addProperty(m_properties["DiffRotDiscreteCircle"]);
hwhmRangeSelector->setVisible(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::bgTypeSelection(int index)
{
if ( index == 2 )
{
m_properties["LinearBackground"]->addSubProperty(m_properties["BGA1"]);
m_properties["LinearBackground"]->removeSubProperty(m_properties["BGA1"]);
using Mantid::Kernel::Exception::NotFoundError;
if(!m_cfInputWS)
{
g_log.error("No workspace loaded, cannot create preview plot.");
return;
}
const bool plotGuess = m_uiForm.ckPlotGuess->isChecked();
m_uiForm.ckPlotGuess->setChecked(false);
int specNo = m_uiForm.spPlotSpectrum->text().toInt();
m_uiForm.ppPlot->clear();
m_uiForm.ppPlot->addSpectrum("Sample", m_cfInputWS, specNo);
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);
}
catch(std::invalid_argument & exc)
{
// 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);
// 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);
}
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()))
bool tieCentres = (m_uiForm.cbFitType->currentIndex() > 1);
CompositeFunction_sptr function = createFunction(tieCentres);
if ( m_cfInputWS == NULL )
{
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];
}
}
FunctionDomain1DVector domain(inputXData);
FunctionValues outputData(domain);
function->function(domain, outputData);
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);
CompositeFunction_sptr function = createFunction(m_uiForm.ckTieCentres->isChecked());
QString fitType = fitTypeString();
QString bgType = backgroundString();
{
g_log.error("No fit type defined!");
}
QString outputNm = runPythonCode(QString("from IndirectCommon import getWSprefix\nprint getWSprefix('") + m_cfInputWSName + QString("')\n")).trimmed();
outputNm += QString("conv_") + fitType + bgType + m_uiForm.spPlotSpectrum->text();
std::string output = outputNm.toStdString();
IAlgorithm_sptr alg = AlgorithmManager::Instance().create("Fit");
alg->initialize();
alg->setPropertyValue("Function", function->asString());
alg->setPropertyValue("InputWorkspace", m_cfInputWSName.toStdString());
alg->setProperty<int>("WorkspaceIndex", m_uiForm.spPlotSpectrum->text().toInt());
alg->setProperty<double>("StartX", m_dblManager->value(m_properties["StartX"]));
alg->setProperty<double>("EndX", m_dblManager->value(m_properties["EndX"]));
alg->setProperty("Output", output);
alg->setProperty("CreateOutput", true);
alg->setProperty("OutputCompositeMembers", true);
alg->setProperty("ConvolveMembers", true);
showMessageBox("Fit algorithm failed.");
m_uiForm.ppPlot->removeSpectrum("Guess");
m_uiForm.ppPlot->addSpectrum("Fit", outputNm+"_Workspace", 1, Qt::red);
IFunction_sptr outputFunc = alg->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];
// 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"]);
int fitTypeIndex = m_uiForm.cbFitType->currentIndex();
//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"]);
// If using a delta function with any fit type or using two Lorentzians
bool usingCompositeFunc = ((usingDeltaFunc && fitTypeIndex > 0) || fitTypeIndex == 2);
if (usingCompositeFunc)
{
key += "f0.";
}
m_dblManager->setValue(m_properties["DeltaHeight"], parameters[key]);