Newer
Older
#include "MantidQtMantidWidgets/MuonFitPropertyBrowser.h"
#include "MantidQtMantidWidgets/PropertyHandler.h"
#include "MantidAPI/FunctionFactory.h"
#include "MantidAPI/MatrixWorkspace.h"
#include "MantidAPI/ITableWorkspace.h"
#include "MantidAPI/TableRow.h"
#include "MantidAPI/WorkspaceFactory.h"
#include "MantidAPI/WorkspaceGroup.h"
#include "MantidKernel/VectorHelper.h"
#include "MantidQtMantidWidgets/StringEditorFactory.h"
#include "MantidQtMantidWidgets/MuonFitDataSelector.h"
#include "MantidAPI/MultiDomainFunction.h"
// Suppress a warning coming out of code that isn't ours
#if defined(__INTEL_COMPILER)
#pragma warning disable 1125
#if (__GNUC__ >= 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic push
#endif
#pragma GCC diagnostic ignored "-Woverloaded-virtual"
#endif
#include "DoubleEditorFactory.h"
#include "qteditorfactory.h"
#if defined(__INTEL_COMPILER)
#pragma warning enable 1125
#if (__GNUC__ >= 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic pop
#endif
#endif
#include "MantidAPI/AlgorithmManager.h"
#include "MantidAPI/FrameworkManager.h"
#include "MantidAPI/CompositeFunction.h"
#include "MantidAPI/Expression.h"
#include "MantidAPI/IBackgroundFunction.h"
#include "MantidAPI/IPeakFunction.h"
#include "qttreepropertybrowser.h"
#include "qtpropertymanager.h"
#include <QSettings>
#include <QMessageBox>
#include <QAction>
#include <QLabel>
#include <QPushButton>
#include <QMenu>
#include <QSignalMapper>
namespace {
Mantid::Kernel::Logger g_log("MuonFitPropertyBrowser");
const QString CUSTOM_LABEL{"Custom"};
const QString ALL_GROUPS_LABEL{"All Groups"};
const QString ALL_PAIRS_LABEL{"All Pairs"};
const QString ALL_PERIODS_LABEL{"All Periods"};
namespace MantidQt {
namespace MantidWidgets {
using namespace Mantid::API;
const std::string MuonFitPropertyBrowser::SIMULTANEOUS_PREFIX{"MuonSimulFit_"};
/**
* Constructor
* @param parent :: The parent widget - must be an ApplicationWindow
* @param mantidui :: The UI form for MantidPlot
*/
MuonFitPropertyBrowser::MuonFitPropertyBrowser(QWidget *parent,
QObject *mantidui)
: FitPropertyBrowser(parent, mantidui), m_widgetSplitter(nullptr),
m_mainSplitter(nullptr) {}
/**
* Initialise the muon fit property browser.
*/
void MuonFitPropertyBrowser::init() {
QWidget *w = new QWidget(this);
QSettings settings;
settings.beginGroup("Mantid/FitBrowser");
/* Create function group */
QtProperty *functionsGroup = m_groupManager->addProperty("Functions");
QtProperty *settingsGroup(NULL);
// Seperates the data and the settings into two seperate categories
settingsGroup = m_groupManager->addProperty("Data");
QSettings multiFitSettings;
multiFitSettings.beginGroup("");
/* Create function group */
QtProperty *multiFitSettingsGroup(NULL);
// Seperates the data and the settings into two seperate categories
multiFitSettingsGroup = m_groupManager->addProperty("Data");
// Have slightly different names as requested by the muon scientists.
m_startX =
addDoubleProperty(QString("Start (%1s)").arg(QChar(0x03BC))); //(mu);
m_endX = addDoubleProperty(QString("End (%1s)").arg(QChar(0x03BC)));
m_normalization = m_enumManager->addProperty("Normalization");
setNormalization();
m_keepNorm = m_boolManager->addProperty("Fix Normalization");
bool keepNorm = settings.value("Fix Normalization", QVariant(false)).toBool();
m_boolManager->setValue(m_keepNorm, keepNorm);
m_workspace = m_enumManager->addProperty("Workspace");
m_workspaceIndex = m_intManager->addProperty("Workspace Index");
m_output = m_stringManager->addProperty("Output");
m_minimizer = m_enumManager->addProperty("Minimizer");
m_minimizers << "Levenberg-Marquardt"
<< "Simplex"
<< "Conjugate gradient (Fletcher-Reeves imp.)"
<< "Conjugate gradient (Polak-Ribiere imp.)"
<< "BFGS";
m_enumManager->setEnumNames(m_minimizer, m_minimizers);
m_costFunction = m_enumManager->addProperty("Cost function");
m_costFunctions << "Least squares"
<< "Ignore positive peaks";
m_enumManager->setEnumNames(m_costFunction, m_costFunctions);
m_plotDiff = m_boolManager->addProperty("Plot Difference");
bool plotDiff = settings.value("Plot Difference", QVariant(true)).toBool();
m_boolManager->setValue(m_plotDiff, plotDiff);
m_evaluationType = m_enumManager->addProperty("Evaluate Function As");
m_evaluationType->setToolTip(
"Consider using Histogram fit which may produce more accurate results.");
m_evaluationTypes << "CentrePoint"
<< "Histogram";
m_enumManager->setEnumNames(m_evaluationType, m_evaluationTypes);
int evaluationType =
settings.value(m_evaluationType->propertyName(), 0).toInt();
m_enumManager->setValue(m_evaluationType, evaluationType);
settingsGroup->addSubProperty(m_workspace);
settingsGroup->addSubProperty(m_workspaceIndex);
settingsGroup->addSubProperty(m_startX);
settingsGroup->addSubProperty(m_normalization);
settingsGroup->addSubProperty(m_keepNorm);
// Disable "Browse" button - use case is that first run will always be the one
// selected on front tab. User will type in the runs they want rather than
// using the Browse button. (If they want to "Browse" they can use front tab).
multiFitSettingsGroup->addSubProperty(m_startX);
multiFitSettingsGroup->addSubProperty(m_endX);
m_groupsToFit = m_enumManager->addProperty("Groups/Pairs to fit");
m_groupsToFitOptions << ALL_GROUPS_LABEL << ALL_PAIRS_LABEL << CUSTOM_LABEL;
m_showGroupValue << "groups";
m_showGroup = m_enumManager->addProperty("Selected Groups");
m_enumManager->setEnumNames(m_groupsToFit, m_groupsToFitOptions);
multiFitSettingsGroup->addSubProperty(m_groupsToFit);
multiFitSettingsGroup->addSubProperty(m_showGroup);
m_enumManager->setEnumNames(m_showGroup, m_showGroupValue);
QString tmp = "fwd";
addGroupCheckbox(tmp);
tmp = "bwd";
addGroupCheckbox(tmp);
m_periodsToFit = m_enumManager->addProperty("Periods to fit");
m_periodsToFitOptions << ALL_PERIODS_LABEL << "1"
<< "2" << CUSTOM_LABEL;
m_showPeriodValue << "1";
m_showPeriods = m_enumManager->addProperty("Selected Periods");
m_enumManager->setEnumNames(m_periodsToFit, m_periodsToFitOptions);
multiFitSettingsGroup->addSubProperty(m_periodsToFit);
multiFitSettingsGroup->addSubProperty(m_showPeriods);
m_enumManager->setEnumNames(m_showPeriods, m_showPeriodValue);
multiFitSettingsGroup->addSubProperty(m_normalization);
/* Create editors and assign them to the managers */
createEditors(w);
updateDecimals();
m_functionsGroup = m_browser->addProperty(functionsGroup);
m_settingsGroup = m_browser->addProperty(settingsGroup);
m_multiFitSettingsGroup = m_browser->addProperty(multiFitSettingsGroup);
connect(m_browser, SIGNAL(currentItemChanged(QtBrowserItem *)), this,
QHBoxLayout *btnLayout = new QHBoxLayout;
m_reselectGroupBtn = new QPushButton("Groups/Pairs");
m_reselectPeriodBtn = new QPushButton("Periods");
m_generateBtn = new QPushButton("Combine Periods");
m_groupWindow = new QDialog(this);
m_periodWindow = new QDialog(this);
m_comboWindow = new QDialog(this);
m_reselectGroupBtn->setEnabled(false);
m_reselectPeriodBtn->setEnabled(false);
connect(m_reselectGroupBtn, SIGNAL(released()), this,
SLOT(groupBtnPressed()));
connect(m_reselectPeriodBtn, SIGNAL(released()), this,
SLOT(periodBtnPressed()));
connect(m_generateBtn, SIGNAL(released()), this, SLOT(generateBtnPressed()));
btnLayout->addWidget(m_reselectGroupBtn);
btnLayout->addWidget(m_reselectPeriodBtn);
btnLayout->addWidget(m_generateBtn);
// Don't show "Function" or "Data" sections as they have separate widgets
m_browser->setItemVisible(m_functionsGroup, false);
m_browser->setItemVisible(m_settingsGroup, false);
m_browser->setItemVisible(m_multiFitSettingsGroup, true);
// Custom settings that are specific and asked for by the muon scientists.
QtProperty *customSettingsGroup = m_groupManager->addProperty("Settings");
m_rawData = m_boolManager->addProperty("Fit To Raw Data");
bool data = settings.value("Fit To Raw Data", QVariant(false)).toBool();
m_boolManager->setValue(m_rawData, data);
m_showParamErrors = m_boolManager->addProperty("Show Parameter Errors");
// XXX: showParamErrors is true by default for Muons
bool showParamErrors =
settings.value(m_showParamErrors->propertyName(), true).toBool();
m_boolManager->setValue(m_showParamErrors, showParamErrors);
m_parameterManager->setErrorsEnabled(showParamErrors);
customSettingsGroup->addSubProperty(m_minimizer);
customSettingsGroup->addSubProperty(m_plotDiff);
customSettingsGroup->addSubProperty(m_rawData);
customSettingsGroup->addSubProperty(m_showParamErrors);
customSettingsGroup->addSubProperty(m_evaluationType);
m_customSettingsGroup = m_browser->addProperty(customSettingsGroup);
// Initialise the layout.
// Create an empty splitter that can hold extra widgets
m_widgetSplitter = new QSplitter(Qt::Vertical, w);
m_widgetSplitter->setSizePolicy(QSizePolicy::Policy::Expanding,
QSizePolicy::Policy::Expanding);
// This splitter separates the "extra widgets" region from the browser
m_mainSplitter = new QSplitter(Qt::Vertical, w);
m_mainSplitter->insertWidget(0, m_widgetSplitter);
m_mainSplitter->insertWidget(1, m_browser);
m_mainSplitter->setStretchFactor(0, 1);
m_mainSplitter->setStretchFactor(1, 0);
// Insert after the buttons
auto parentLayout = qobject_cast<QVBoxLayout *>(w->layout());
if (parentLayout) {
const int index = parentLayout->count() - 1;
constexpr int stretchFactor = 10; // so these widgets get any extra space
parentLayout->insertWidget(index, m_mainSplitter, stretchFactor);
parentLayout->setSpacing(0);
parentLayout->setMargin(0);
parentLayout->setContentsMargins(0, 0, 0, 0);
parentLayout->insertWidget(index + 1, m_btnGroup);
// Update tooltips when function structure is (or might've been) changed in
// any way
connect(this, SIGNAL(functionChanged()), SLOT(updateStructureTooltips()));
void MuonFitPropertyBrowser::executeFitMenu(const QString &item) {
emit functionUpdateRequested();
} else {
FitPropertyBrowser::executeFitMenu(item);
}
// Create group/pair selection pop up
void MuonFitPropertyBrowser::groupBtnPressed() { genGroupWindow(); }
void MuonFitPropertyBrowser::periodBtnPressed() { genPeriodWindow(); }
void MuonFitPropertyBrowser::generateBtnPressed() { genCombinePeriodWindow(); }
* This initialization includes:
* 1. SIGNALs/SLOTs when properties change.
* 2. Actions and associated SIGNALs/SLOTs.
* @param fitMapper the QMap to the fit mapper
* @param fitMenu the QMenu for the fit button
void MuonFitPropertyBrowser::populateFitMenuButton(QSignalMapper *fitMapper,
QMenu *fitMenu) {
m_fitActionTFAsymm = new QAction("TF Asymmetry Fit", this);
fitMapper->setMapping(m_fitActionTFAsymm, "TFAsymm");
FitPropertyBrowser::populateFitMenuButton(fitMapper, fitMenu);
connect(m_fitActionTFAsymm, SIGNAL(triggered()), fitMapper, SLOT(map()));
fitMenu->addAction(m_fitActionTFAsymm);
/// Enable/disable the Fit button;
void MuonFitPropertyBrowser::setFitEnabled(bool yes) {
m_fitActionFit->setEnabled(yes);
m_fitActionSeqFit->setEnabled(yes);
if (!m_boolManager->value(m_keepNorm) && yes) {
else {
m_fitActionTFAsymm->setEnabled(false);
}
}
/**
* Set the input workspace name
*/
void MuonFitPropertyBrowser::setWorkspaceName(const QString &wsName) {
int i = m_workspaceNames.indexOf(wsName);
if (i < 0) {
// workspace may not be found because add notification hasn't been processed
// yet
populateWorkspaceNames();
i = m_workspaceNames.indexOf(wsName);
}
if (i >= 0)
m_enumManager->setValue(m_workspace, i);
* @param prop :: A pointer to the function name property
*/
void MuonFitPropertyBrowser::enumChanged(QtProperty *prop) {
if (!m_changeSlotsEnabled)
return;
if (prop == m_groupsToFit) {
int j = m_enumManager->value(m_groupsToFit);
QString option = m_groupsToFitOptions[j];
if (option == ALL_GROUPS_LABEL) {
setAllGroups();
m_reselectGroupBtn->setEnabled(false);
} else if (option == ALL_PAIRS_LABEL) {
setAllPairs();
m_reselectGroupBtn->setEnabled(false);
} else if (option == CUSTOM_LABEL) {
m_reselectGroupBtn->setEnabled(true);
genGroupWindow();
}
updateGroupDisplay();
} else if (prop == m_periodsToFit) {
int j = m_enumManager->value(m_periodsToFit);
QString option = m_periodsToFitOptions[j];
if (option == CUSTOM_LABEL) {
m_reselectPeriodBtn->setEnabled(true);
genPeriodWindow();
} else if (option == ALL_PERIODS_LABEL) {
setAllPeriods();
m_reselectPeriodBtn->setEnabled(false);
} else {
for (auto iter = m_periodBoxes.constBegin();
iter != m_periodBoxes.constEnd(); ++iter) {
m_boolManager->setValue(iter.value(), true);
} else {
m_boolManager->setValue(iter.value(), false);
}
m_reselectPeriodBtn->setEnabled(false);
}
}
updatePeriodDisplay();
} else if (prop == m_workspace) {
// make sure the output is updated
FitPropertyBrowser::enumChanged(prop);
int j = m_enumManager->value(m_workspace);
std::string option = m_workspaceNames[j].toStdString();
setOutputName(option);
} else {
* selected groups
*/
void MuonFitPropertyBrowser::updateGroupDisplay() {
auto tmp = getChosenGroups().join(",").toStdString();
m_showGroupValue << getChosenGroups().join(",");
m_enumManager->setEnumNames(m_showGroup, m_showGroupValue);
m_multiFitSettingsGroup->property()->addSubProperty(m_showGroup);
}
/** Sets the display for
* selected periods
*/
void MuonFitPropertyBrowser::updatePeriodDisplay() {
m_showPeriodValue.clear();
auto tmp = getChosenPeriods();
tmp.replaceInStrings(QRegExp(","), "+");
m_showPeriodValue << tmp.join(",");
m_enumManager->setEnumNames(m_showPeriods, m_showPeriodValue);
if (m_periodsToFitOptions.size() > 1) {
m_multiFitSettingsGroup->property()->addSubProperty(m_showPeriods);
}
/** Called when a double property changed
* @param prop :: A pointer to the property
void MuonFitPropertyBrowser::doubleChanged(QtProperty *prop) {
if (!m_changeSlotsEnabled)
return;
double value = m_doubleManager->value(prop);
if (prop == m_startX) {
// call setWorkspace to change maxX in functions
setWorkspace(m_compositeFunction);
getHandler()->setAttribute(QString("Start (%1s)").arg(QChar(0x03BC)),
value); // (mu)
emit startXChanged(startX());
emit xRangeChanged(startX(), endX());
return;
} else if (prop == m_endX) {
// call setWorkspace to change minX in functions
setWorkspace(m_compositeFunction);
getHandler()->setAttribute(QString("End (%1s)").arg(QChar(0x03BC)), value);
emit endXChanged(endX());
emit xRangeChanged(startX(), endX());
return;
MantidQt::MantidWidgets::PropertyHandler *h =
getHandler()->findHandler(prop);
if (!h)
return;
QtProperty *parProp = h->getParameterProperty(prop);
if (parProp) {
if (prop->propertyName() == "LowerBound") {
double loBound = m_doubleManager->value(prop);
h->addConstraint(parProp, true, false, loBound, 0);
} else if (prop->propertyName() == "UpperBound") {
double upBound = m_doubleManager->value(prop);
h->addConstraint(parProp, false, true, 0, upBound);
} else { // it could be an attribute
h->setAttribute(prop);
}
}
}
/** @returns the normalization
*/
double MuonFitPropertyBrowser::normalization() const {
}
void MuonFitPropertyBrowser::setNormalization() {
setNormalization(workspaceName());
}
/**
* @param name :: the ws name to get normalization for
* @returns the normalization
*/
void MuonFitPropertyBrowser::setNormalization(const std::string name) {
m_normalizationValue.clear();
QString label;
auto norms = readMultipleNormalization();
std::string tmp =name;
// stored with ; instead of spaces
std::replace(tmp.begin(), tmp.end(), ' ', ';');
auto it = norms.find(tmp);
if (it == norms.end()) {
label = QString::fromStdString("N/A");
}
else {
label = QString::number(it->second);
}
m_normalizationValue.append(label);
m_enumManager->setEnumNames(m_normalization, m_normalizationValue);
/** Called when a bool property changed
* @param prop :: A pointer to the property
*/
void MuonFitPropertyBrowser::boolChanged(QtProperty *prop) {
if (prop == m_rawData) {
const bool val = m_boolManager->value(prop);
emit fitRawDataClicked(val);
if (prop == m_keepNorm) {
const bool val = m_boolManager->value(prop);
if (val) { // record data for later
double norm = readNormalization()[0];
ITableWorkspace_sptr table = WorkspaceFactory::Instance().createTable();
AnalysisDataService::Instance().addOrReplace("__keepNorm__", table);
table->addColumn("double", "norm");
table->addColumn("int", "spectra");
TableRow row = table->appendRow();
row << norm << 0;
// remove TFAsymm fit
m_fitActionTFAsymm->setEnabled(false);
} else { // remove data so it is not used later
AnalysisDataService::Instance().remove("__keepNorm__");
// if fit is enabled so should TFAsymm
if (m_fitActionSeqFit->isEnabled()) {
m_fitActionTFAsymm->setEnabled(true);
}
}
// search map for group/pair change
bool done = false;
for (auto iter = m_groupBoxes.constBegin(); iter != m_groupBoxes.constEnd();
++iter) {
if (iter.value() == prop) {
done = true;
updateGroupDisplay();
emit groupBoxClicked();
}
}
// search map for period change
if (done == false) {
for (auto iter = m_periodBoxes.constBegin();
iter != m_periodBoxes.constEnd(); ++iter) {
if (iter.value() == prop) {
done = true;
updatePeriodDisplay();
emit periodBoxClicked();
}
}
}
if (done == false) {
// defer to parent class
FitPropertyBrowser::boolChanged(prop);
}
/**
*Get the registered function names
*/
void MuonFitPropertyBrowser::populateFunctionNames() {
const std::vector<std::string> names = FunctionFactory::Instance().getKeys();
m_registeredFunctions.clear();
m_registeredPeaks.clear();
m_registeredBackgrounds.clear();
for (size_t i = 0; i < names.size(); i++) {
std::string fnName = names[i];
QString qfnName = QString::fromStdString(fnName);
if (qfnName == "MultiBG")
continue;
auto f = FunctionFactory::Instance().createFunction(fnName);
const std::vector<std::string> categories = f->categories();
bool muon = false;
for (size_t j = 0; j < categories.size(); ++j) {
if ((categories[j] == "Muon") || (categories[j] == "General") ||
(categories[j] == "Background"))
m_registeredFunctions << qfnName;
}
IPeakFunction *pf = dynamic_cast<IPeakFunction *>(f.get());
// CompositeFunction* cf = dynamic_cast<CompositeFunction*>(f.get());
if (pf) {
m_registeredPeaks << qfnName;
} else if (dynamic_cast<IBackgroundFunction *>(f.get())) {
m_registeredBackgrounds << qfnName;
m_registeredOther << qfnName;
}
}
}
/**
* Creates an instance of Fit algorithm, sets its properties and launches it.
*/
void MuonFitPropertyBrowser::doTFAsymmFit() {
std::string wsName = workspaceName();
if (wsName.empty()) {
QMessageBox::critical(this, "Mantid - Error", "Workspace name is not set");
return;
}
std::vector<double> normVec;
auto norms= readMultipleNormalization();
// TFAsymm calculation -> there is already some estimated data
//rescale WS to normalized counts:
const int nWorkspaces = static_cast<int>(m_workspacesToFit.size());
for (int i = 0; i < nWorkspaces; i++) {
rescaleWS(norms, m_workspacesToFit[i], 1.0);
std::string tmp = m_workspacesToFit[i];
std::replace(tmp.begin(), tmp.end(), ' ', ';');
//The order of the input is the same
// as the order of the workspace list
// create a vec of norms in the same order
auto it = norms.find(tmp);
normVec.push_back(it->second);
}
try {
m_initialParameters.resize(compositeFunction()->nParams());
for (size_t i = 0; i < compositeFunction()->nParams(); i++) {
m_initialParameters[i] = compositeFunction()->getParameter(i);
}
m_fitActionUndoFit->setEnabled(true);
IAlgorithm_sptr alg = AlgorithmManager::Instance().create("Fit");
alg->initialize();
if (m_compositeFunction->name() == "MultiBG") {
alg->setPropertyValue("Function", "");
IFunction_sptr userFunc = getFittingFunction();
auto TFAsymmFunc = getTFAsymmFitFunction(userFunc,normVec);
alg->setProperty("Function",TFAsymmFunc);
alg->setPropertyValue("InputWorkspace", wsName + "_Raw");
alg->setPropertyValue("InputWorkspace", wsName);
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
alg->setProperty("WorkspaceIndex", workspaceIndex());
alg->setProperty("StartX", startX());
alg->setProperty("EndX", endX());
alg->setPropertyValue("Minimizer", minimizer());
alg->setPropertyValue("CostFunction", costFunction());
// If we are doing a simultaneous fit, set this up here
const int nWorkspaces = static_cast<int>(m_workspacesToFit.size());
if (nWorkspaces > 1) {
alg->setPropertyValue("InputWorkspace", m_workspacesToFit[0]);
// Remove existing results with the same name
if (AnalysisDataService::Instance().doesExist(outputName())) {
AnalysisDataService::Instance().deepRemoveGroup(outputName());
}
for (int i = 1; i < nWorkspaces; i++) {
std::string suffix = boost::lexical_cast<std::string>(i);
alg->setPropertyValue("InputWorkspace_" + suffix, m_workspacesToFit[i]);
alg->setProperty("WorkspaceIndex_" + suffix, workspaceIndex());
alg->setProperty("StartX_" + suffix, startX());
alg->setProperty("EndX_" + suffix, endX());
}
}
else {
setSingleFitLabel(wsName);
}
alg->setPropertyValue("Output", outputName());
observeFinish(alg);
alg->execute();
// get norms
std::vector<double> newNorms;
IFunction_sptr outputFunction = alg->getProperty("Function");
for (size_t j = 0; j < nWorkspaces; j++) {
std::string paramName = "f" + std::to_string(j);
paramName += ".f0.f0.A0";
newNorms.push_back(outputFunction->getParameter(paramName));
std::string tmpWSName = m_workspacesToFit[j];
if (rawData()) { // store norms without the raw
tmpWSName = tmpWSName.substr(0, tmpWSName.size() - 4);
auto tmpWSNameNoRaw = tmpWSName;
std::replace(tmpWSName.begin(), tmpWSName.end(), ' ', ';');
auto it = norms.find(tmpWSName);
it->second = newNorms[newNorms.size() - 1];
//transform data back to Asymm
//rescale WS:
rescaleWS(norms, tmpWSNameNoRaw, -1.0);
updateMultipleNormalization(norms);
}
catch (const std::exception &e) {
QString msg = "TF Asymmetry Fit failed.\n\n" + QString(e.what()) + "\n";
QMessageBox::critical(this, "Mantid - Error", msg);
//setNormalization();
void MuonFitPropertyBrowser::updateMultipleNormalization(std::map<std::string, double> norms) {
auto oldNorm = readMultipleNormalization();
ITableWorkspace_sptr table = WorkspaceFactory::Instance().createTable();
AnalysisDataService::Instance().addOrReplace("MuonAnalysisTFNormalizations", table);
table->addColumn("double", "norm");
table->addColumn("str", "name");
table->addColumn("str", "method");
for (auto norm : oldNorm) {
Mantid::API::TableRow row = table->appendRow();
auto it = norms.find(std::get<0>(norm));
if (it != norms.end() && it->second != std::get<1>(norm)) {
//write new norm
row << it->second << std::get<0>(norm) << "Calculated";//pass calc or est
}
else {
//write old norm
row << std::get<1>(norm) << std::get<0>(norm) << "Estimated";
}
}
}
/** Gets the fitting function for TFAsymmetry fit
* @param original :: The function defined by the user (in GUI)
* @param norms :: vector of normalization constants
* @returns :: The fitting function for the TFAsymmetry fit
*/
Mantid::API::IFunction_sptr MuonFitPropertyBrowser::getTFAsymmFitFunction(Mantid::API::IFunction_sptr original,const std::vector<double> norms) {
auto multi = boost::make_shared<MultiDomainFunction>();
auto tmp = boost::dynamic_pointer_cast<MultiDomainFunction> (original);
size_t numDomains = original->getNumberDomains();
for (size_t j = 0; j < numDomains; j++) {
IFunction_sptr userFunc;
auto constant = FunctionFactory::Instance().createInitialized("name = FlatBackground, A0 = 1.0, ties = (A0 = 1.0)");
if (numDomains == 1) {
userFunc = original;
}else {
userFunc = tmp->getFunction(j);
multi->setDomainIndex(j, j);
}
auto inBrace = boost::make_shared <CompositeFunction>();
inBrace->addFunction(constant);
inBrace->addFunction(userFunc);
auto norm = FunctionFactory::Instance().createInitialized("composite=CompositeFunction,NumDeriv=true;name = FlatBackground, A0 =" + std::to_string(norms[j]));
auto product = boost::dynamic_pointer_cast<CompositeFunction> (FunctionFactory::Instance().createFunction("ProductFunction"));
product->addFunction(inBrace);
multi->addFunction(product);
}
return boost::dynamic_pointer_cast<IFunction> (multi);
std::vector<double> readNormalization() {
std::vector<double> norm;
if (!AnalysisDataService::Instance().doesExist("__norm__")) {
norm.push_back(22.423);
} else {
Mantid::API::ITableWorkspace_sptr table =
boost::dynamic_pointer_cast<Mantid::API::ITableWorkspace>(
Mantid::API::AnalysisDataService::Instance().retrieve("__norm__"));
auto colNorm = table->getColumn("norm");
for (size_t j = 0; j < table->rowCount(); j++) {
norm.push_back((*colNorm)[j]); // record and update norm....
}
}
return norm;
/** Reads the normalization constants and which WS
* they belong to
* @returns :: A map of normalization constants and WS names
*/
std::map<std::string, double> readMultipleNormalization() {
std::map<std::string,double> norm;
if (AnalysisDataService::Instance().doesExist("MuonAnalysisTFNormalizations")) {
Mantid::API::ITableWorkspace_sptr table =
boost::dynamic_pointer_cast<Mantid::API::ITableWorkspace>(
Mantid::API::AnalysisDataService::Instance().retrieve("MuonAnalysisTFNormalizations"));
auto colNorm = table->getColumn("norm");
auto colName = table->getColumn("name");
for (size_t j = 0; j < table->rowCount(); j++) {
norm[colName->cell<std::string>(j)]=((*colNorm)[j]); // read norm
}
}
return norm;
}
/** The transformation between normalized counts and asymmetry
* @param norm :: map of normalization constants
* @param WSName :: the name of the WS to rescale
* @param shift :: offset to add (+1 = to normalized counts, -1 = to asymmetry)
*/
void MuonFitPropertyBrowser::rescaleWS(const std::map<std::string, double>norm,const std::string wsName,const double shift) {
//get norm:
std::string tmp = wsName;
// stored with ; instead of spaces
std::replace(tmp.begin(), tmp.end(), ' ', ';');
auto it = norm.find(tmp);
if (it == norm.end()) {
g_log.error("WS not found: "+wsName);
return;
}
double value = it->second;
rescaleWS(value, wsName, shift);
if (rawData()) {
rescaleWS(value, wsName+"_Raw", shift);
}
}
/** The transformation between normalized counts and asymmetry
* @param value :: normalization constants
* @param WSName :: the name of the WS to rescale
* @param shift :: offset to add (+1 = to normalized counts, -1 = to asymmetry)
*/
void MuonFitPropertyBrowser::rescaleWS(const double value, const std::string wsName, const double shift) {
//go back to normalized counts
if (shift == 1.0) {
IAlgorithm_sptr alg = AlgorithmManager::Instance().create("Scale");
alg->initialize();
alg->setProperty("InputWorkspace", wsName);
alg->setProperty("OutputWorkspace", wsName);
alg->setProperty("Factor", 1.0);
alg->setProperty("Operation", "Add");
alg->execute();
}
IAlgorithm_sptr alg = AlgorithmManager::Instance().create("Scale");
alg->initialize();
alg->setProperty("InputWorkspace", wsName);
alg->setProperty("OutputWorkspace", wsName);
if (shift == 1) {
alg->setProperty("Factor", value);
}
else {
alg->setProperty("Factor", 1. / value);
}
alg->setProperty("Operation", "Multiply");
alg->execute();
// if to asymmetry
IAlgorithm_sptr alg = AlgorithmManager::Instance().create("Scale");
alg->initialize();
alg->setProperty("InputWorkspace", wsName);
alg->setProperty("OutputWorkspace", wsName);
alg->setProperty("Factor", -1.0);
alg->setProperty("Operation", "Add");
alg->execute();
}
}
* Requests checks and updates prior to running a fit
void MuonFitPropertyBrowser::fit() { emit preFitChecksRequested(false); }
/**
* Creates an instance of Fit algorithm, sets its properties and launches it.
*/
void MuonFitPropertyBrowser::runFit() {
std::string wsName = workspaceName();
if (wsName.empty()) {
QMessageBox::critical(this, "Mantid - Error", "Workspace name is not set");
m_initialParameters.resize(compositeFunction()->nParams());
for (size_t i = 0; i < compositeFunction()->nParams(); i++) {
m_initialParameters[i] = compositeFunction()->getParameter(i);
}
m_fitActionUndoFit->setEnabled(true);
// Delete any existing results for this workspace, UNLESS we are doing a
// simultaneous fit
if (m_workspacesToFit.size() < 2) {
if (AnalysisDataService::Instance().doesExist(
wsName + "_NormalisedCovarianceMatrix")) {
FrameworkManager::Instance().deleteWorkspace(
wsName + "_NormalisedCovarianceMatrix");
}
if (AnalysisDataService::Instance().doesExist(wsName + "_Parameters")) {
FrameworkManager::Instance().deleteWorkspace(wsName + "_Parameters");
}
if (AnalysisDataService::Instance().doesExist(wsName + "_Workspace")) {
FrameworkManager::Instance().deleteWorkspace(wsName + "_Workspace");
}
IAlgorithm_sptr alg = AlgorithmManager::Instance().create("Fit");
alg->initialize();
if (m_compositeFunction->name() == "MultiBG") {
alg->setPropertyValue("Function", "");
} else if (m_compositeFunction->nFunctions() > 1) {
alg->setProperty("Function", boost::dynamic_pointer_cast<IFunction>(
m_compositeFunction));
} else {
alg->setProperty("Function", boost::dynamic_pointer_cast<IFunction>(
m_compositeFunction->getFunction(0)));
}
alg->setPropertyValue("InputWorkspace", wsName + "_Raw");
alg->setPropertyValue("InputWorkspace", wsName);
alg->setProperty("WorkspaceIndex", workspaceIndex());
alg->setProperty("StartX", startX());
alg->setProperty("EndX", endX());
alg->setPropertyValue("Minimizer", minimizer());
alg->setPropertyValue("CostFunction", costFunction());
// If we are doing a simultaneous fit, set this up here
const int nWorkspaces = static_cast<int>(m_workspacesToFit.size());
if (nWorkspaces > 1) {
alg->setPropertyValue("InputWorkspace", m_workspacesToFit[0]);
// Remove existing results with the same name
if (AnalysisDataService::Instance().doesExist(outputName())) {
AnalysisDataService::Instance().deepRemoveGroup(outputName());
}
for (int i = 1; i < nWorkspaces; i++) {
std::string suffix = boost::lexical_cast<std::string>(i);
alg->setPropertyValue("InputWorkspace_" + suffix, m_workspacesToFit[i]);
alg->setProperty("WorkspaceIndex_" + suffix, workspaceIndex());
alg->setProperty("StartX_" + suffix, startX());
alg->setProperty("EndX_" + suffix, endX());
}
observeFinish(alg);
alg->executeAsync();
} catch (const std::exception &e) {
QString msg = "Fit algorithm failed.\n\n" + QString(e.what()) + "\n";
QMessageBox::critical(this, "Mantid - Error", msg);
/**
* Show sequential fit dialog.
*/
void MuonFitPropertyBrowser::runSequentialFit() {
emit sequentialFitRequested();
}
/**
* Requests checks and updates prior to running a sequential fit
*/
void MuonFitPropertyBrowser::sequentialFit() {
emit preFitChecksRequested(true);
* Connect to the AnalysisDataService when shown
void MuonFitPropertyBrowser::showEvent(QShowEvent *e) {
(void)e;
observePostDelete();
populateWorkspaceNames();
}
/** Check if the workspace can be used in the fit. The accepted types are
* MatrixWorkspaces same size and that it isn't the generated raw file.
* @param ws :: The workspace
*/
bool MuonFitPropertyBrowser::isWorkspaceValid(Workspace_sptr ws) const {
QString workspaceName(QString::fromStdString(ws->getName()));
if ((workspaceName.contains("_Raw")) ||
(workspaceName.contains("MuonAnalysis")))
return false;
// Exclude fitting results
if (workspaceName.endsWith("_Workspace"))
return dynamic_cast<MatrixWorkspace *>(ws.get()) != 0;
}
void MuonFitPropertyBrowser::finishHandle(const IAlgorithm *alg) {
// Copy experiment info to output workspace
if (AnalysisDataService::Instance().doesExist(outputName() + "_Workspace")) {
// Input workspace should be a MatrixWorkspace according to isWorkspaceValid
auto inWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
static_cast<std::string>(alg->getProperty("InputWorkspace")));
auto outWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
outputName() + "_Workspace");
if (inWs && outWs) {
outWs->copyExperimentInfoFrom(inWs.get());
}
} else if (AnalysisDataService::Instance().doesExist(outputName() +
"_Workspaces")) {
// Output workspace was a group
auto outGroup = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(
outputName() + "_Workspaces");
if (outGroup->size() == m_workspacesToFit.size()) {
for (size_t i = 0; i < outGroup->size(); i++) {
auto outWs =
boost::dynamic_pointer_cast<MatrixWorkspace>(outGroup->getItem(i));
auto inWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
m_workspacesToFit[i]);
if (inWs && outWs) {
outWs->copyExperimentInfoFrom(inWs.get());
}
// If fit was simultaneous, insert extra information into params table
const int nWorkspaces = static_cast<int>(m_workspacesToFit.size());
if (nWorkspaces > 1) {
finishAfterSimultaneousFit(alg, nWorkspaces);