Mantid
Loading...
Searching...
No Matches
MuonFitPropertyBrowser.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
11#include "MantidAPI/TableRow.h"
16#include "MantidQtWidgets/Common/QtPropertyBrowser/StringEditorFactory.h"
17
20
21// Suppress a warning coming out of code that isn't ours
22#if defined(__INTEL_COMPILER)
23#pragma warning disable 1125
24#elif defined(__GNUC__)
25#if (__GNUC__ >= 4 && __GNUC_MINOR__ >= 6)
26#pragma GCC diagnostic push
27#endif
28#pragma GCC diagnostic ignored "-Woverloaded-virtual"
29#endif
30#include "MantidQtWidgets/Common/QtPropertyBrowser/DoubleEditorFactory.h"
31#include "MantidQtWidgets/Common/QtPropertyBrowser/qteditorfactory.h"
32#if defined(__INTEL_COMPILER)
33#pragma warning enable 1125
34#elif defined(__GNUC__)
35#if (__GNUC__ >= 4 && __GNUC_MINOR__ >= 6)
36#pragma GCC diagnostic pop
37#endif
38#endif
39
46
47#include "MantidQtWidgets/Common/QtPropertyBrowser/qtpropertymanager.h"
48#include "MantidQtWidgets/Common/QtPropertyBrowser/qttreepropertybrowser.h"
49
50#include <Poco/ActiveResult.h>
51
52#include <QAction>
53#include <QFormLayout>
54#include <QMessageBox>
55#include <QSettings>
56
57#include <QLabel>
58#include <QLayout>
59#include <QPushButton>
60#include <QSplitter>
61
62#include <QCheckBox>
63#include <QMenu>
64#include <QMessageBox>
65#include <QSignalMapper>
66#include <QTableWidgetItem>
67#include <utility>
68
69namespace {
70Mantid::Kernel::Logger g_log("MuonFitPropertyBrowser");
71const QString CUSTOM_LABEL{"Custom"};
72const QString ALL_GROUPS_LABEL{"All Groups"};
73const QString ALL_PAIRS_LABEL{"All Pairs"};
74const QString ALL_PERIODS_LABEL{"All Periods"};
75const std::string UNNORM = "_unNorm";
76} // namespace
77
78namespace MantidQt {
79namespace MantidWidgets {
80
81using namespace Mantid::API;
82
83const std::string MuonFitPropertyBrowser::SIMULTANEOUS_PREFIX = {"MuonSimulFit_"};
84
90MuonFitPropertyBrowser::MuonFitPropertyBrowser(QWidget *parent, QObject *mantidui)
91 : FitPropertyBrowser(parent, mantidui), m_widgetSplitter(nullptr), m_mainSplitter(nullptr),
92 m_isMultiFittingMode(false) {}
93
98 QWidget *w = new QWidget(this);
99
100 QSettings settings;
101 settings.beginGroup("Mantid/FitBrowser");
102
103 /* Create function group */
104 QtProperty *functionsGroup = m_groupManager->addProperty("Functions");
105 QtProperty *settingsGroup(nullptr);
106
107 // Seperates the data and the settings into two seperate categories
108 settingsGroup = m_groupManager->addProperty("Data");
109
110 QSettings multiFitSettings;
111 multiFitSettings.beginGroup("");
112
113 /* Create function group */
114 QtProperty *multiFitSettingsGroup(nullptr);
115
116 // Seperates the data and the settings into two seperate categories
117 multiFitSettingsGroup = m_groupManager->addProperty("Data");
118
119 // Have slightly different names as requested by the muon scientists.
120 m_startX = addDoubleProperty(QString("Start (%1s)").arg(QChar(0x03BC))); //(mu);
121 m_endX = addDoubleProperty(QString("End (%1s)").arg(QChar(0x03BC)));
122
123 m_normalization = m_enumManager->addProperty("Normalization");
125
126 m_keepNorm = m_boolManager->addProperty("Fix Normalization");
127 bool keepNorm = settings.value("Fix Normalization", QVariant(false)).toBool();
128 m_boolManager->setValue(m_keepNorm, keepNorm);
129
130 m_workspace = m_enumManager->addProperty("Workspace");
131 m_workspaceIndex = m_intManager->addProperty("Workspace Index");
132 m_output = m_stringManager->addProperty("Output");
133 m_minimizer = m_enumManager->addProperty("Minimizer");
134 m_minimizers << "Levenberg-Marquardt"
135 << "Simplex"
136 << "Conjugate gradient (Fletcher-Reeves imp.)"
137 << "Conjugate gradient (Polak-Ribiere imp.)"
138 << "BFGS";
139 m_enumManager->setEnumNames(m_minimizer, m_minimizers);
140 m_costFunction = m_enumManager->addProperty("Cost function");
141 m_costFunctions << "Least squares"
142 << "Ignore positive peaks";
144
145 m_plotDiff = m_boolManager->addProperty("Plot Difference");
146 bool plotDiff = settings.value("Plot Difference", QVariant(true)).toBool();
148
149 m_evaluationType = m_enumManager->addProperty("Evaluate Function As");
150 m_evaluationType->setToolTip("Consider using Histogram fit which may produce more accurate results.");
151 m_evaluationTypes << "CentrePoint"
152 << "Histogram";
154 int evaluationType = settings.value(m_evaluationType->propertyName(), 0).toInt();
155 m_enumManager->setValue(m_evaluationType, evaluationType);
156
157 settingsGroup->addSubProperty(m_workspace);
158 settingsGroup->addSubProperty(m_workspaceIndex);
159 settingsGroup->addSubProperty(m_startX);
160 settingsGroup->addSubProperty(m_endX);
161 settingsGroup->addSubProperty(m_normalization);
162 settingsGroup->addSubProperty(m_keepNorm);
163
164 // Disable "Browse" button - use case is that first run will always be the one
165 // selected on front tab. User will type in the runs they want rather than
166 // using the Browse button. (If they want to "Browse" they can use front tab).
167
168 multiFitSettingsGroup->addSubProperty(m_startX);
169 multiFitSettingsGroup->addSubProperty(m_endX);
170 m_groupsToFit = m_enumManager->addProperty("Groups/Pairs to fit");
171 m_groupsToFitOptions << ALL_GROUPS_LABEL << ALL_PAIRS_LABEL << CUSTOM_LABEL;
172 m_showGroupValue << "groups";
173 m_showGroup = m_enumManager->addProperty("Selected Groups");
175 multiFitSettingsGroup->addSubProperty(m_groupsToFit);
176 multiFitSettingsGroup->addSubProperty(m_showGroup);
177
179 m_enumManager->setValue(m_groupsToFit, 2);
181 QString tmp = "fwd";
183 tmp = "bwd";
185 m_periodsToFit = m_enumManager->addProperty("Periods to fit");
186 m_periodsToFitOptions << ALL_PERIODS_LABEL << CUSTOM_LABEL << "1"
187 << "2";
188 m_showPeriodValue << "1";
189 m_showPeriods = m_enumManager->addProperty("Selected Periods");
191 multiFitSettingsGroup->addSubProperty(m_periodsToFit);
192 multiFitSettingsGroup->addSubProperty(m_showPeriods);
194
195 multiFitSettingsGroup->addSubProperty(m_normalization);
196
197 /* Create editors and assign them to the managers */
198 createEditors(w);
199
201
202 m_functionsGroup = m_browser->addProperty(functionsGroup);
203 m_settingsGroup = m_browser->addProperty(settingsGroup);
204 m_multiFitSettingsGroup = m_browser->addProperty(multiFitSettingsGroup);
205 connect(m_browser, SIGNAL(currentItemChanged(QtBrowserItem *)), this, SLOT(currentItemChanged(QtBrowserItem *)));
206
207 m_btnGroup = new QGroupBox(tr("Reselect Data"));
208 auto *btnLayout = new QHBoxLayout;
209 m_reselectGroupBtn = new QPushButton("Groups/Pairs");
210 m_reselectPeriodBtn = new QPushButton("Periods");
211 m_generateBtn = new QPushButton("Combine Periods");
212 m_groupWindow = new QDialog(this);
213 m_periodWindow = new QDialog(this);
214 m_comboWindow = new QDialog(this);
215
216 m_reselectGroupBtn->setEnabled(false);
217 m_reselectPeriodBtn->setEnabled(false);
218 connect(m_reselectGroupBtn, SIGNAL(released()), this, SLOT(groupBtnPressed()));
219 connect(m_reselectPeriodBtn, SIGNAL(released()), this, SLOT(periodBtnPressed()));
220 connect(m_generateBtn, SIGNAL(released()), this, SLOT(generateBtnPressed()));
221
222 btnLayout->addWidget(m_reselectGroupBtn);
223 btnLayout->addWidget(m_reselectPeriodBtn);
224 btnLayout->addWidget(m_generateBtn);
225
226 m_btnGroup->setLayout(btnLayout);
227
228 // Don't show "Function" or "Data" sections as they have separate widgets
229 m_browser->setItemVisible(m_functionsGroup, false);
230 m_browser->setItemVisible(m_settingsGroup, false);
231 m_browser->setItemVisible(m_multiFitSettingsGroup, true);
232 // Custom settings that are specific and asked for by the muon scientists.
233 QtProperty *customSettingsGroup = m_groupManager->addProperty("Settings");
234
235 m_rawData = m_boolManager->addProperty("Fit To Raw Data");
236 bool data = settings.value("Fit To Raw Data", QVariant(false)).toBool();
237 m_boolManager->setValue(m_rawData, data);
238
239 m_showParamErrors = m_boolManager->addProperty("Show Parameter Errors");
240 // XXX: showParamErrors is true by default for Muons
241 bool showParamErrors = settings.value(m_showParamErrors->propertyName(), true).toBool();
242 m_boolManager->setValue(m_showParamErrors, showParamErrors);
243 m_parameterManager->setErrorsEnabled(showParamErrors);
244
245 m_TFAsymmMode = m_boolManager->addProperty("TF Asymmetry Mode");
246 bool TFAsymmMode = settings.value("TF Asymmetry Mode", QVariant(false)).toBool();
247 m_boolManager->setValue(m_TFAsymmMode, TFAsymmMode);
248
249 customSettingsGroup->addSubProperty(m_minimizer);
250 customSettingsGroup->addSubProperty(m_TFAsymmMode);
251 customSettingsGroup->addSubProperty(m_plotDiff);
252 customSettingsGroup->addSubProperty(m_rawData);
253 customSettingsGroup->addSubProperty(m_showParamErrors);
254 customSettingsGroup->addSubProperty(m_evaluationType);
255
256 m_customSettingsGroup = m_browser->addProperty(customSettingsGroup);
257
258 // Initialise the layout.
260
261 // Create an empty splitter that can hold extra widgets
262 m_widgetSplitter = new QSplitter(Qt::Vertical, w);
263 m_widgetSplitter->setSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding);
264
265 // This splitter separates the "extra widgets" region from the browser
266 m_mainSplitter = new QSplitter(Qt::Vertical, w);
267 m_mainSplitter->insertWidget(0, m_widgetSplitter);
268 m_mainSplitter->insertWidget(1, m_browser);
269 m_mainSplitter->setStretchFactor(0, 1);
270 m_mainSplitter->setStretchFactor(1, 0);
271
272 // Insert after the buttons
273 auto parentLayout = qobject_cast<QVBoxLayout *>(w->layout());
274 if (parentLayout) {
275 const int index = parentLayout->count() - 1;
276 constexpr int stretchFactor = 10; // so these widgets get any extra space
277 parentLayout->insertWidget(index, m_mainSplitter, stretchFactor);
278
279 parentLayout->setSpacing(0);
280 parentLayout->setMargin(0);
281 parentLayout->setContentsMargins(0, 0, 0, 0);
282 parentLayout->insertWidget(index + 1, m_btnGroup);
283 }
284 // Update tooltips when function structure is (or might've been) changed in
285 // any way
286 connect(this, SIGNAL(functionChanged()), SLOT(updateStructureTooltips()));
287 // disable TFAsymm mode by default
288 setTFAsymmMode(TFAsymmMode);
290}
291// Set up the execution of the muon fit menu
292void MuonFitPropertyBrowser::executeFitMenu(const QString &item) {
293 if (item == "Fit" && m_boolManager->value(m_TFAsymmMode)) {
294 doTFAsymmFit();
295 } else {
297 }
298}
299// Create group/pair selection pop up
301// Create period selection pop up
303// Create combination selection pop up
305
308 m_fitActionFit->setEnabled(yes);
309 m_fitActionSeqFit->setEnabled(yes);
310}
311
313 if (count() == 0) {
314 setFitEnabled(false);
315 } else {
316 setFitEnabled(true);
317 }
318}
322void MuonFitPropertyBrowser::setWorkspaceName(const QString &wsName) {
323 int i = m_workspaceNames.indexOf(wsName);
324 if (i < 0) {
325 // workspace may not be found because add notification hasn't been processed
326 // yet
328 i = m_workspaceNames.indexOf(wsName);
329 }
330 if (i >= 0)
331 m_enumManager->setValue(m_workspace, i);
332}
337 if (m_workspaceNames.empty()) {
338 if (this->isVisible()) {
339 g_log.error("No Data available. Please load Some data.");
340 }
341 return;
342 }
344 return;
345 if (prop == m_groupsToFit) {
346 int j = m_enumManager->value(m_groupsToFit);
347 QString option = m_groupsToFitOptions[j];
348
349 if (option == ALL_GROUPS_LABEL) {
350 setAllGroups();
351 m_reselectGroupBtn->setEnabled(false);
352 } else if (option == ALL_PAIRS_LABEL) {
353 setAllPairs();
354 m_reselectGroupBtn->setEnabled(false);
355 } else if (option == CUSTOM_LABEL) {
356 m_reselectGroupBtn->setEnabled(true);
358 }
360
361 } else if (prop == m_periodsToFit) {
362 int j = m_enumManager->value(m_periodsToFit);
363 QString option = m_periodsToFitOptions[j];
364 if (option == CUSTOM_LABEL) {
365 m_reselectPeriodBtn->setEnabled(true);
367 } else if (option == ALL_PERIODS_LABEL) {
369 m_reselectPeriodBtn->setEnabled(false);
370 } else {
371 for (auto iter = m_periodBoxes.constBegin(); iter != m_periodBoxes.constEnd(); ++iter) {
372 if (option == iter.key()) {
373 m_boolManager->setValue(iter.value(), true);
374 } else {
375 m_boolManager->setValue(iter.value(), false);
376 }
377 m_reselectPeriodBtn->setEnabled(false);
378 }
379 }
381 } else if (prop == m_workspace) {
382 int j = m_enumManager->value(m_workspace);
383 std::string option = m_workspaceNames[j].toStdString();
384 // update plot
385 emit workspaceNameChanged(QString::fromStdString(option));
386
387 setOutputName(option);
388 // only do this if in single fit mode
389 if (m_periodBoxes.size() > 1 && !m_browser->isItemVisible(m_multiFitSettingsGroup)) {
390 size_t end = 0;
391 // assumed structure of name
392 // isolate the period
393 for (int k = 0; k < 4; k++) {
394 end = option.find_first_of(";");
395 option = option.substr(end + 1, option.size());
396 }
397 end = option.find_first_of(";");
398 QString selectedPeriod = QString::fromStdString(option.substr(0, end));
399 // turn on only the relevant box
400 for (auto iter = m_periodBoxes.constBegin(); iter != m_periodBoxes.constEnd(); ++iter) {
401 m_boolManager->setValue(iter.value(), selectedPeriod == iter.key());
402 }
403 }
404 if (!m_browser->isItemVisible(m_multiFitSettingsGroup)) {
405 size_t end = 0;
406 // assumed structure of name
407 // isolate the group/pair
408 for (int k = 0; k < 2; k++) {
409 end = option.find_first_of(";");
410 option = option.substr(end + 1, option.size());
411 }
412 end = option.find_first_of(";");
413
414 boost::erase_all(option, " ");
415
416 auto tmp = option.substr(0, end - 1);
417 QString selectedGroup = QString::fromStdString(tmp);
418 // turn on only the relevant box
419 for (auto iter = m_groupBoxes.constBegin(); iter != m_groupBoxes.constEnd(); ++iter) {
420 m_boolManager->setValue(iter.value(), selectedGroup == iter.key());
421 }
422 }
423 // update plot for TF Asymm mode
424 updateTFPlot();
425
426 } else {
428 }
429}
434 m_showGroupValue.clear();
435 m_showGroupValue << getChosenGroups().join(",");
437 m_multiFitSettingsGroup->property()->addSubProperty(m_showGroup);
438}
443 m_showPeriodValue.clear();
444 auto tmp = getChosenPeriods();
445 tmp.replaceInStrings(QRegExp(","), "+");
446 m_showPeriodValue << tmp.join(",");
448 if (m_periodsToFitOptions.size() > 1) {
449 m_multiFitSettingsGroup->property()->addSubProperty(m_showPeriods);
450 }
451}
457 return;
458
459 double value = m_doubleManager->value(prop);
460 if (prop == m_startX) {
461 // call setWorkspace to change maxX in functions
463 getHandler()->setAttribute(QString("Start (%1s)").arg(QChar(0x03BC)),
464 value); // (mu)
465 emit startXChanged(startX());
466 emit xRangeChanged(startX(), endX());
467 return;
468 } else if (prop == m_endX) {
469 // call setWorkspace to change minX in functions
471 getHandler()->setAttribute(QString("End (%1s)").arg(QChar(0x03BC)), value);
472 emit endXChanged(endX());
473 emit xRangeChanged(startX(), endX());
474 return;
475 } else { // check if it is a constraint
477 if (!h)
478 return;
479
480 QtProperty *parProp = h->getParameterProperty(prop);
481 if (parProp) {
482 if (prop->propertyName() == "LowerBound") {
483 double loBound = m_doubleManager->value(prop);
484 h->addConstraint(parProp, true, false, loBound, 0);
485 } else if (prop->propertyName() == "UpperBound") {
486 double upBound = m_doubleManager->value(prop);
487 h->addConstraint(parProp, false, true, 0, upBound);
488 }
489 } else { // it could be an attribute
490 h->setAttribute(prop);
491 }
492 }
493}
494
500void MuonFitPropertyBrowser::setNormalization(const std::string &name) {
501 m_normalizationValue.clear();
502 QString label;
503 auto norms = readMultipleNormalization();
504 std::string tmp = name;
505 if (rawData()) {
506 tmp = tmp + "_Raw";
507 }
508 // stored with ; instead of spaces
509 std::replace(tmp.begin(), tmp.end(), ' ', ';');
510 auto it = norms.find(tmp);
511 if (it == norms.end()) {
512 label = QString::fromStdString("N/A");
513 } else {
514 label = QString::number(it->second);
515 }
516 m_normalizationValue.append(label);
518}
519
524 if (prop == m_rawData) {
525 const bool val = m_boolManager->value(prop);
526 emit fitRawDataClicked(val);
527 }
528 if (prop == m_TFAsymmMode) {
529 const bool val = m_boolManager->value(prop);
530 setTFAsymmMode(val);
531 }
532 if (prop == m_keepNorm) {
533 const bool val = m_boolManager->value(prop);
534 if (val) { // record data for later
535 double norm = 0.0;
536 int j = m_enumManager->value(m_workspace);
537 std::string name = m_workspaceNames[j].toStdString();
538
539 auto norms = readMultipleNormalization();
540 std::string tmp = name;
541 if (rawData()) {
542 tmp = tmp + "_Raw";
543 }
544 // stored with ; instead of spaces
545 std::replace(tmp.begin(), tmp.end(), ' ', ';');
546 auto it = norms.find(tmp);
547 if (it != norms.end()) {
548 norm = it->second;
549 }
550 ITableWorkspace_sptr table = WorkspaceFactory::Instance().createTable();
551 AnalysisDataService::Instance().addOrReplace("__keepNorm__", table);
552 table->addColumn("double", "norm");
553 table->addColumn("int", "spectra");
554 TableRow row = table->appendRow();
555 row << norm << 0;
556
557 } else { // remove data so it is not used later
558 AnalysisDataService::Instance().remove("__keepNorm__");
559 }
560 } else {
561 // search map for group/pair change
562 bool done = false;
563 for (auto iter = m_groupBoxes.constBegin(); iter != m_groupBoxes.constEnd(); ++iter) {
564 if (iter.value() == prop) {
565 done = true;
567 emit groupBoxClicked();
568 }
569 }
570 // search map for period change
571 if (done == false) {
572 for (auto iter = m_periodBoxes.constBegin(); iter != m_periodBoxes.constEnd(); ++iter) {
573 if (iter.value() == prop) {
574 done = true;
576 emit periodBoxClicked();
577 }
578 }
579 }
580 if (done == false) {
581 // defer to parent class
583 }
584 }
585}
586
591 const std::vector<std::string> names = FunctionFactory::Instance().getKeys();
592 m_registeredFunctions.clear();
593 m_registeredPeaks.clear();
595 for (auto fnName : names) {
596 QString qfnName = QString::fromStdString(fnName);
597 if (qfnName == "MultiBG")
598 continue;
599
600 auto f = FunctionFactory::Instance().createFunction(fnName);
601 const std::vector<std::string> categories = f->categories();
602 bool muon = false;
603 for (const auto &category : categories) {
604 if ((category == "Muon") || (category == "General") || (category == "Background"))
605 muon = true;
606 }
607 if (muon) {
608 m_registeredFunctions << qfnName;
609 }
610 IPeakFunction *pf = dynamic_cast<IPeakFunction *>(f.get());
611 // CompositeFunction* cf = dynamic_cast<CompositeFunction*>(f.get());
612 if (pf) {
613 m_registeredPeaks << qfnName;
614 } else if (dynamic_cast<IBackgroundFunction *>(f.get())) {
615 m_registeredBackgrounds << qfnName;
616 } else {
617 m_registeredOther << qfnName;
618 }
619 }
620}
621std::string MuonFitPropertyBrowser::getUnnormName(std::string wsName) {
622 if (wsName.find(UNNORM) == std::string::npos) {
623 auto raw = wsName.find("_Raw");
624
625 if (raw == std::string::npos) {
626 wsName += TFExtension();
627 } else {
628 wsName.insert(raw, UNNORM);
629 }
630 }
631 if (rawData() && wsName.find("_Raw") == std::string::npos) {
632 wsName += "_Raw";
633 }
634 return wsName;
635}
636
641 std::string wsName = workspaceName();
642 wsName = getUnnormName(wsName);
643 if (wsName.empty()) {
644 QMessageBox::critical(this, "Mantid - Error", "Workspace name is not set");
645 return;
646 }
647 try {
648 m_initialParameters.resize(compositeFunction()->nParams());
649 for (size_t i = 0; i < compositeFunction()->nParams(); i++) {
650 m_initialParameters[i] = compositeFunction()->getParameter(i);
651 }
652 m_fitActionUndoFit->setEnabled(true);
653
654 // Delete any existing results for this workspace, UNLESS we are doing a
655 // simultaneous fit
656 if (m_workspacesToFit.size() < 2) {
657 if (AnalysisDataService::Instance().doesExist(wsName + "_NormalisedCovarianceMatrix")) {
658 FrameworkManager::Instance().deleteWorkspace(wsName + "_NormalisedCovarianceMatrix");
659 }
660 if (AnalysisDataService::Instance().doesExist(wsName + "_Parameters")) {
661 FrameworkManager::Instance().deleteWorkspace(wsName + "_Parameters");
662 }
663 if (AnalysisDataService::Instance().doesExist(wsName + "_Workspace")) {
664 FrameworkManager::Instance().deleteWorkspace(wsName + "_Workspace");
665 }
666 }
667
668 IAlgorithm_sptr alg = AlgorithmManager::Instance().create("CalculateMuonAsymmetry");
669 alg->initialize();
670 auto fa = m_compositeFunction->asString();
671 if (m_compositeFunction->nFunctions() > 1) {
672
673 alg->setProperty("InputFunction", std::dynamic_pointer_cast<IFunction>(m_functionBrowser->getGlobalFunction()));
674 } else {
675 alg->setProperty("InputFunction", std::dynamic_pointer_cast<IFunction>(m_compositeFunction->getFunction(0)));
676 }
677
678 auto unnorm = m_workspacesToFit;
679 std::string tmp = UNNORM;
680 bool raw = rawData();
681 std::for_each(unnorm.begin(), unnorm.end(), [tmp, raw](std::string &wsName) {
682 if (wsName.find(UNNORM) == std::string::npos) {
683 auto rawIndex = wsName.find("_Raw");
684
685 if (rawIndex == std::string::npos) {
686 wsName += UNNORM;
687 } else {
688 wsName.insert(rawIndex, UNNORM);
689 }
690 }
691 if (raw && wsName.find("_Raw") == std::string::npos) {
692 wsName += "_Raw";
693 }
694 });
695
696 alg->setProperty("UnNormalizedWorkspaceList", unnorm);
697 alg->setProperty("ReNormalizedWorkspaceList", m_workspacesToFit);
698 alg->setProperty("NormalizationTable", "MuonAnalysisTFNormalizations");
699
700 alg->setProperty("StartX", startX());
701 alg->setProperty("EndX", endX());
702 alg->setPropertyValue("Minimizer", minimizer());
703
704 // If we are doing a simultaneous fit, set this up here
705 const int nWorkspaces = static_cast<int>(m_workspacesToFit.size());
706 std::string output = outputName();
707 if (nWorkspaces == 1) {
708 setSingleFitLabel(wsName);
709 output = getUnnormName(output);
710 }
711
712 alg->setPropertyValue("OutputFitWorkspace", output);
713
714 observeFinish(alg);
715 alg->execute();
716
717 } catch (const std::exception &e) {
718 QString msg = "CalculateMuonAsymmetry algorithm failed.\n\n" + QString(e.what()) + "\n";
719 QMessageBox::critical(this, "Mantid - Error", msg);
720 }
721}
726std::map<std::string, double> readMultipleNormalization() {
727 std::map<std::string, double> norm;
728 if (AnalysisDataService::Instance().doesExist("MuonAnalysisTFNormalizations")) {
729 Mantid::API::ITableWorkspace_sptr table = std::dynamic_pointer_cast<Mantid::API::ITableWorkspace>(
730 Mantid::API::AnalysisDataService::Instance().retrieve("MuonAnalysisTFNormalizations"));
731 auto colNorm = table->getColumn("norm");
732 auto colName = table->getColumn("name");
733 for (size_t j = 0; j < table->rowCount(); j++) {
734 norm[colName->cell<std::string>(j)] = ((*colNorm)[j]); // read norm
735 }
736 }
737 return norm;
738}
742void MuonFitPropertyBrowser::fit() { emit preFitChecksRequested(false); }
743
747void MuonFitPropertyBrowser::runFit() {
748 std::string wsName = workspaceName();
749 if (wsName.empty()) {
750 QMessageBox::critical(this, "Mantid - Error", "Workspace name is not set");
751 return;
752 }
753 try {
754 m_initialParameters.resize(compositeFunction()->nParams());
755 for (size_t i = 0; i < compositeFunction()->nParams(); i++) {
756 m_initialParameters[i] = compositeFunction()->getParameter(i);
757 }
758 m_fitActionUndoFit->setEnabled(true);
759
760 // Delete any existing results for this workspace, UNLESS we are doing a
761 // simultaneous fit
762 if (m_workspacesToFit.size() < 2) {
763 if (AnalysisDataService::Instance().doesExist(wsName + "_NormalisedCovarianceMatrix")) {
764 FrameworkManager::Instance().deleteWorkspace(wsName + "_NormalisedCovarianceMatrix");
765 }
766 if (AnalysisDataService::Instance().doesExist(wsName + "_Parameters")) {
767 FrameworkManager::Instance().deleteWorkspace(wsName + "_Parameters");
768 }
769 if (AnalysisDataService::Instance().doesExist(wsName + "_Workspace")) {
770 FrameworkManager::Instance().deleteWorkspace(wsName + "_Workspace");
771 }
772 }
773
774 IAlgorithm_sptr alg = AlgorithmManager::Instance().create("Fit");
775 alg->initialize();
776 if (m_compositeFunction->name() == "MultiBG") {
777 alg->setPropertyValue("Function", "");
778 } else if (m_compositeFunction->nFunctions() > 1) {
779 alg->setProperty("Function", std::dynamic_pointer_cast<IFunction>(m_compositeFunction));
780 } else {
781 alg->setProperty("Function", std::dynamic_pointer_cast<IFunction>(m_compositeFunction->getFunction(0)));
782 }
783 if (rawData())
784 alg->setPropertyValue("InputWorkspace", wsName + "_Raw");
785 else
786 alg->setPropertyValue("InputWorkspace", wsName);
787 alg->setProperty("WorkspaceIndex", workspaceIndex());
788 alg->setProperty("StartX", startX());
789 alg->setProperty("EndX", endX());
790 alg->setPropertyValue("Minimizer", minimizer());
791 alg->setPropertyValue("CostFunction", costFunction());
792
793 // If we are doing a simultaneous fit, set this up here
794 const int nWorkspaces = static_cast<int>(m_workspacesToFit.size());
795 if (nWorkspaces > 1) {
796 alg->setPropertyValue("InputWorkspace", m_workspacesToFit[0]);
797 for (int i = 1; i < nWorkspaces; i++) {
798 std::string suffix = boost::lexical_cast<std::string>(i);
799 alg->setPropertyValue("InputWorkspace_" + suffix, m_workspacesToFit[i]);
800 alg->setProperty("WorkspaceIndex_" + suffix, workspaceIndex());
801 alg->setProperty("StartX_" + suffix, startX());
802 alg->setProperty("EndX_" + suffix, endX());
803 }
804 } else {
805 setSingleFitLabel(wsName);
806 }
807 alg->setPropertyValue("Output", outputName());
808
809 observeFinish(alg);
810 alg->executeAsync();
811 } catch (const std::exception &e) {
812 QString msg = "Fit algorithm failed.\n\n" + QString(e.what()) + "\n";
813 QMessageBox::critical(this, "Mantid - Error", msg);
814 }
815}
816
820void MuonFitPropertyBrowser::runSequentialFit() { emit sequentialFitRequested(); }
821
825void MuonFitPropertyBrowser::sequentialFit() { emit preFitChecksRequested(true); }
826
830void MuonFitPropertyBrowser::showEvent(QShowEvent *e) {
831 (void)e;
832 observePostDelete();
833 populateWorkspaceNames();
834}
835
840bool MuonFitPropertyBrowser::isWorkspaceValid(Workspace_sptr ws) const {
841 QString workspaceName(QString::fromStdString(ws->getName()));
842
843 if ((workspaceName.contains("_Raw")) || (workspaceName.contains("MuonAnalysis")))
844 return false;
845
846 // Exclude fitting results
847 if (workspaceName.endsWith("_Workspace"))
848 return false;
849
850 return dynamic_cast<MatrixWorkspace *>(ws.get()) != nullptr;
851}
852
853void MuonFitPropertyBrowser::setFitWorkspaces(const std::string &input) {
854 // Copy experiment info to output workspace
855 if (AnalysisDataService::Instance().doesExist(outputName() + "_Workspace")) {
856 // Input workspace should be a MatrixWorkspace according to isWorkspaceValid
857 auto inWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(input);
858 auto outWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(outputName() + "_Workspace");
859 if (inWs && outWs) {
860 outWs->copyExperimentInfoFrom(inWs.get());
861 }
862 } else if (AnalysisDataService::Instance().doesExist(outputName() + "_Workspaces")) {
863 // Output workspace was a group
864 auto outGroup = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(outputName() + "_Workspaces");
865 if (outGroup->size() == m_workspacesToFit.size()) {
866 for (size_t i = 0; i < outGroup->size(); i++) {
867 auto outWs = std::dynamic_pointer_cast<MatrixWorkspace>(outGroup->getItem(i));
868 auto inWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(m_workspacesToFit[i]);
869 if (inWs && outWs) {
870 outWs->copyExperimentInfoFrom(inWs.get());
871 }
872 }
873 }
874 }
875}
876
877void MuonFitPropertyBrowser::finishHandle(const IAlgorithm *alg) {
878 if (alg->name() == "CalculateMuonAsymmetry") {
879 finishHandleTF(alg);
880 } else {
881 finishHandleNormal(alg);
882 }
883}
884void MuonFitPropertyBrowser::finishHandleTF(const IAlgorithm *alg) {
885
886 setFitWorkspaces(static_cast<std::string>(alg->getProperty("UnNormalizedWorkspaceList")));
887
888 auto status = QString::fromStdString(alg->getPropertyValue("OutputStatus"));
889 emit fitResultsChanged(status);
890 FitPropertyBrowser::fitResultsChanged(status);
891
892 // If fit was simultaneous, insert extra information into params table
893 // and group the output workspaces
894 const int nWorkspaces = static_cast<int>(m_workspacesToFit.size());
895 if (nWorkspaces > 1) {
896 std::string baseName = outputName();
897 finishAfterTFSimultaneousFit(alg, baseName);
898 }
899
900 getFitResults();
901 std::vector<std::string> wsList = alg->getProperty("UnNormalizedWorkspaceList");
902 emit fittingDone(QString::fromStdString(wsList[0]));
903 double quality = alg->getProperty("ChiSquared");
904 // std::string costFunction =
905
906 emit changeWindowTitle(QString("Fit Function (") + "Chi-sq " + " = " + QString::number(quality) + ", " + status +
907 ")");
908 if (nWorkspaces == 1) {
909 emit algorithmFinished(QString::fromStdString(wsList[0] + "_workspace"));
910 }
911}
912void MuonFitPropertyBrowser::finishHandleNormal(const IAlgorithm *alg) {
913 // Copy experiment info to output workspace
914 setFitWorkspaces(static_cast<std::string>(alg->getProperty("InputWorkspace")));
915 // If fit was simultaneous, insert extra information into params table
916 // and group the output workspaces
917 const int nWorkspaces = static_cast<int>(m_workspacesToFit.size());
918 if (nWorkspaces > 1) {
919 finishAfterSimultaneousFit(alg, nWorkspaces);
920 }
921
922 FitPropertyBrowser::finishHandle(alg);
923}
924
932// need own version of this
933void MuonFitPropertyBrowser::finishAfterSimultaneousFit(const Mantid::API::IAlgorithm *fitAlg,
934 const int nWorkspaces) const {
935 AnalysisDataServiceImpl &ads = AnalysisDataService::Instance();
936 try {
937 const std::string paramTableName = fitAlg->getProperty("OutputParameters");
938 const auto paramTable = ads.retrieveWS<ITableWorkspace>(paramTableName);
939 if (paramTable) {
940 Mantid::API::TableRow f0Row = paramTable->appendRow();
941 f0Row << "f0=" + fitAlg->getPropertyValue("InputWorkspace") << 0.0 << 0.0;
942 for (int i = 1; i < nWorkspaces; i++) {
943 const std::string suffix = boost::lexical_cast<std::string>(i);
944
945 const auto wsName = fitAlg->getPropertyValue("InputWorkspace_" + suffix);
946 Mantid::API::TableRow row = paramTable->appendRow();
947 row << "f" + suffix + "=" + wsName << 0.0 << 0.0;
948 }
949 }
951 // Not a fatal error, but shouldn't happen
952 g_log.warning("Could not find output parameters table for simultaneous fit");
953 }
954
955 // Group output together
956 std::string groupName = fitAlg->getPropertyValue("Output");
957 const std::string &baseName = groupName;
958
959 // Create a group for label
960 try {
961 ads.addOrReplace(groupName, std::make_shared<WorkspaceGroup>());
962 ads.addToGroup(groupName, baseName + "_NormalisedCovarianceMatrix");
963 ads.addToGroup(groupName, baseName + "_Parameters");
964 ads.addToGroup(groupName, baseName + "_Workspaces");
965 } catch (const Mantid::Kernel::Exception::NotFoundError &err) {
966 g_log.warning(err.what());
967 }
968}
969
977void MuonFitPropertyBrowser::finishAfterTFSimultaneousFit(const Mantid::API::IAlgorithm *alg,
978 const std::string &baseName) const {
979 AnalysisDataServiceImpl &ads = AnalysisDataService::Instance();
980 try {
981 std::vector<std::string> wsList = alg->getProperty("UnNormalizedWorkspaceList");
982 std::string paramTableName = baseName + "_Parameters";
983 const auto paramTable = ads.retrieveWS<ITableWorkspace>(paramTableName);
984 if (paramTable) {
985 for (size_t i = 0; i < wsList.size(); i++) {
986 const std::string suffix = boost::lexical_cast<std::string>(i);
987
988 const auto wsName = wsList[i];
989 Mantid::API::TableRow row = paramTable->appendRow();
990 row << "f" + suffix + "=" + wsName << 0.0 << 0.0;
991 }
992 }
994 // Not a fatal error, but shouldn't happen
995 g_log.warning("Could not find output parameters table for simultaneous fit");
996 }
997
998 // Group output together
999
1000 std::string groupName = baseName;
1001 // Create a group for label
1002 try {
1003 ads.addOrReplace(groupName, std::make_shared<WorkspaceGroup>());
1004 ads.addToGroup(groupName, baseName + "_NormalisedCovarianceMatrix");
1005 ads.addToGroup(groupName, baseName + "_Parameters");
1006 ads.addToGroup(groupName, baseName + "_Workspaces");
1007 } catch (const Mantid::Kernel::Exception::NotFoundError &err) {
1008 g_log.warning(err.what());
1009 }
1010}
1015void MuonFitPropertyBrowser::addExtraWidget(QWidget *widget) {
1016 widget->setSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding);
1017 if (m_widgetSplitter) {
1018 m_widgetSplitter->addWidget(widget);
1019 }
1020}
1021
1026void MuonFitPropertyBrowser::setFunction(const IFunction_sptr func) { createCompositeFunction(func); }
1027
1032void MuonFitPropertyBrowser::setWorkspaceNames(const QStringList &wsNames) {
1033 m_workspacesToFit.clear();
1034 std::transform(wsNames.begin(), wsNames.end(), std::back_inserter(m_workspacesToFit),
1035 [](const QString &qs) { return qs.toStdString(); });
1036 // Update listeners
1037 emit workspacesToFitChanged(static_cast<int>(m_workspacesToFit.size()));
1038 // Update norm
1039 setNormalization();
1040}
1041
1047std::string MuonFitPropertyBrowser::outputName() const {
1048 const int nWorkspaces = static_cast<int>(m_workspacesToFit.size());
1049 if (nWorkspaces > 1) {
1050 // simultaneous fit
1051 return SIMULTANEOUS_PREFIX + m_simultaneousLabel;
1052 } else {
1053 // use parent class behaviour
1054
1055 return FitPropertyBrowser::outputName();
1056 }
1057}
1058
1068void MuonFitPropertyBrowser::setMultiFittingMode(bool enabled) {
1069 m_isMultiFittingMode = enabled;
1070 // First, clear whatever model is currently set
1071 this->clear();
1072 // set default selection (all groups)
1073 if (enabled) {
1074 setAllGroups();
1075 setAllPeriods();
1076 setAutoBackgroundName("");
1077 this->clear(); // force update of composite function
1078 } else { // clear current selection
1079 if (m_autoBackground != "") {
1080 setAutoBackgroundName(m_autoBackground);
1081 addAutoBackground();
1082 }
1083 clearChosenGroups();
1084 clearChosenPeriods();
1085 }
1086 // Show or hide "Function" and "Data" sections
1087 m_browser->setItemVisible(m_functionsGroup, !enabled);
1088 m_browser->setItemVisible(m_settingsGroup, !enabled);
1089 m_browser->setItemVisible(m_multiFitSettingsGroup, enabled);
1090 m_btnGroup->setVisible(enabled);
1091 // Show or hide additional widgets
1092 for (int i = 0; i < m_widgetSplitter->count(); ++i) {
1093 if (auto *widget = m_widgetSplitter->widget(i)) {
1094 widget->setVisible(enabled);
1095 }
1096 }
1097 if (enabled) {
1098 setFitEnabled(false);
1099 }
1100}
1101
1107bool MuonFitPropertyBrowser::isMultiFittingMode() const { return m_isMultiFittingMode; }
1108void MuonFitPropertyBrowser::ConvertFitFunctionForMuonTFAsymmetry(bool enabled) {
1109 // set new fit func
1110 IAlgorithm_sptr alg = AlgorithmManager::Instance().create("ConvertFitFunctionForMuonTFAsymmetry");
1111 // do not preserve the ties
1112 if (AnalysisDataService::Instance().doesExist("MuonAnalysisTFNormalizations") &&
1113 m_compositeFunction->nFunctions() > 0) {
1114 alg->initialize();
1115 IFunction_sptr old = std::dynamic_pointer_cast<IFunction>(m_compositeFunction);
1116
1117 QStringList globals;
1118
1119 if (m_isMultiFittingMode) {
1120 // manually set the function values
1121 old = m_functionBrowser->getGlobalFunction();
1122 globals = m_functionBrowser->getGlobalParameters();
1123 } else if (!enabled && !m_isMultiFittingMode) {
1124 old = std::dynamic_pointer_cast<CompositeFunction>(old);
1125 }
1126 alg->setProperty("InputFunction", old);
1127 alg->setProperty("NormalizationTable", "MuonAnalysisTFNormalizations");
1128 alg->setProperty("WorkspaceList", m_workspacesToFit);
1129 std::string mode = (enabled) ? "Construct" : "Extract";
1130 alg->setProperty("Mode", mode);
1131 alg->execute();
1132 if (!alg->isExecuted()) {
1133 return;
1134 }
1135 IFunction_sptr func = alg->getProperty("OutputFunction");
1136
1137 // multiple fit
1138 if (m_isMultiFittingMode) {
1139 // update values in browser
1140 if (func->getNumberDomains() > 1) {
1141 auto tmp = std::dynamic_pointer_cast<MultiDomainFunction>(func);
1142 old = tmp->getFunction(0);
1143 } else {
1144 old = func;
1145 }
1146 m_functionBrowser->setFunction(old);
1147 // preserve global parameters
1148 QStringList newGlobals;
1149 const std::string INSERT_FUNCTION{"f0.f1.f1."};
1150 if (enabled) {
1151 for (auto global : globals) {
1152 newGlobals << QString::fromStdString(INSERT_FUNCTION) + global;
1153 }
1154 } else {
1155 for (auto global : globals) {
1156 newGlobals << global.remove(0, 9);
1157 }
1158 }
1159 m_functionBrowser->updateMultiDatasetParameters(*func);
1160
1161 m_functionBrowser->setGlobalParameters(newGlobals);
1162 // if multi data set we need to do the fixes manually
1163 // the current domain is automatic
1164 auto originalNames = func->getParameterNames();
1165 for (auto name : originalNames) {
1166 auto index = func->parameterIndex(name);
1167 if (func->isFixed(index) && func->getNumberDomains() > 1) {
1168 // get domain
1169 auto separatorIndex = name.find_first_of(".");
1170 std::string domainStr = name.substr(1, separatorIndex - 1);
1171 int domain = std::stoi(domainStr);
1172 // remove domain from name
1173 auto newName = name.substr(separatorIndex + 1);
1174 // set fix
1175 m_functionBrowser->setLocalParameterFixed(QString::fromStdString(newName), domain, true);
1176 }
1177 }
1178 } // single fit
1179 else {
1180 FitPropertyBrowser::clear();
1181 m_functionBrowser->setFunction(func);
1182 }
1183
1184 updateTFPlot();
1185 }
1186}
1187
1195void MuonFitPropertyBrowser::setTFAsymmMode(bool enabled) {
1196 IFunction_sptr old = std::dynamic_pointer_cast<IFunction>(m_compositeFunction);
1197 if (old->nParams() > 0) {
1198 ConvertFitFunctionForMuonTFAsymmetry(enabled);
1199 // Show or hide the TFAsymmetry fit
1200 if (enabled) {
1201 m_settingsGroup->property()->addSubProperty(m_keepNorm);
1202 } else {
1203 m_settingsGroup->property()->removeSubProperty(m_keepNorm);
1204 }
1205 } else if (enabled) {
1206 // will update when user clicks elsewhere
1207 m_boolManager->setValue(m_TFAsymmMode, false);
1208 QMessageBox::warning(this, "Muon Analysis",
1209 "No fitting function provided. TF Asymmetry mode "
1210 "requires a fitting function to be added before "
1211 "enabling. Please add a fitting function and enable "
1212 "TF Asymmetry Mode again.");
1213 }
1214}
1215std::string MuonFitPropertyBrowser::TFExtension() const { return (m_boolManager->value(m_TFAsymmMode)) ? UNNORM : ""; }
1219void MuonFitPropertyBrowser::updateTFPlot() {
1220 // update plot
1221 int j = m_enumManager->value(m_workspace);
1222 std::string option = m_workspaceNames[j].toStdString();
1223 if (m_boolManager->value(m_TFAsymmMode) && option.find(UNNORM) == std::string::npos) {
1224 auto raw = option.find("_Raw");
1225
1226 if (raw == std::string::npos) {
1227 option += TFExtension();
1228 } else {
1229 option.insert(raw, UNNORM);
1230 }
1231 }
1232 // update plot
1233 emit TFPlot(QString::fromStdString(option));
1234}
1235
1241void MuonFitPropertyBrowser::addFitBrowserWidget(QWidget *widget,
1243 widget->setSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding);
1244 if (m_widgetSplitter) {
1245 m_widgetSplitter->addWidget(widget);
1246 }
1247 m_functionBrowser = functionBrowser;
1248}
1254void MuonFitPropertyBrowser::continueAfterChecks(bool sequential) { emit functionUpdateAndFitRequested(sequential); }
1255
1260bool MuonFitPropertyBrowser::hasGuess() const {
1261 auto *handler = getHandler();
1262 if (handler) {
1263 const bool hasPlot = handler->hasPlot(); // don't allow caller to modify
1264 return hasPlot;
1265 } else {
1266 return false;
1267 }
1268}
1274void MuonFitPropertyBrowser::setAvailableGroups(const QStringList &groups) {
1275 // If it's the same list, do nothing
1276 auto selected = getChosenGroups();
1277 if (groups.size() == m_groupBoxes.size()) {
1278 auto existingGroups = m_groupBoxes.keys();
1279 auto newGroups = groups;
1280 qSort(existingGroups);
1281 qSort(newGroups);
1282 if (existingGroups == newGroups) {
1283 return;
1284 }
1285 }
1286 clearGroupCheckboxes();
1287 QSettings settings;
1288 for (const auto &group : groups) {
1289 addGroupCheckbox(group);
1290 }
1291 // sets the same selection as before
1292 for (const auto &group : selected) {
1293
1294 for (auto iter = m_groupBoxes.constBegin(); iter != m_groupBoxes.constEnd(); ++iter) {
1295 if (iter.key().toStdString() == group.toStdString()) {
1296 m_boolManager->setValue(iter.value(), true);
1297 }
1298 }
1299 }
1300}
1305void MuonFitPropertyBrowser::setChosenGroup(const QString &group) {
1306 clearChosenGroups();
1307 for (auto iter = m_groupBoxes.constBegin(); iter != m_groupBoxes.constEnd(); ++iter) {
1308 if (iter.key() == group) {
1309 m_boolManager->setValue(iter.value(), true);
1310 }
1311 }
1312}
1317void MuonFitPropertyBrowser::clearGroupCheckboxes() {
1318 for (const auto &checkbox : m_groupBoxes) {
1319 delete (checkbox);
1320 }
1321 m_groupBoxes.clear();
1322}
1328void MuonFitPropertyBrowser::addGroupCheckbox(const QString &name) {
1329 m_groupBoxes.insert(name, m_boolManager->addProperty(name));
1330}
1335QStringList MuonFitPropertyBrowser::getChosenGroups() const {
1336 QStringList chosen;
1337 for (auto iter = m_groupBoxes.constBegin(); iter != m_groupBoxes.constEnd(); ++iter) {
1338 if (m_boolManager->value(iter.value()) == true) {
1339 chosen.append(iter.key());
1340 }
1341 }
1342 return chosen;
1343}
1347void MuonFitPropertyBrowser::clearChosenGroups() const {
1348 for (auto iter = m_groupBoxes.constBegin(); iter != m_groupBoxes.constEnd(); ++iter) {
1349 m_boolManager->setValue(iter.value(), false);
1350 }
1351}
1352
1356void MuonFitPropertyBrowser::setAllGroups() {
1357
1358 clearChosenGroups();
1359 for (auto iter = m_groupBoxes.constBegin(); iter != m_groupBoxes.constEnd(); ++iter) {
1360 for (const auto &group : m_groupsList) {
1361 if (iter.key().toStdString() == group) {
1362 m_boolManager->setValue(iter.value(), true);
1363 }
1364 }
1365 }
1366}
1367/*
1368 * Sets all pairs
1369 */
1370void MuonFitPropertyBrowser::setAllPairs() {
1371 clearChosenGroups();
1372 for (auto iter = m_groupBoxes.constBegin(); iter != m_groupBoxes.constEnd(); ++iter) {
1373 const auto keyString = iter.key().toStdString();
1374 const bool isItGroup = std::any_of(m_groupsList.cbegin(), m_groupsList.cend(),
1375 [&keyString](const auto &group) { return group == keyString; });
1376 if (!isItGroup) {
1377 m_boolManager->setValue(iter.value(), true);
1378 }
1379 }
1380}
1381
1382/*
1383 * Create a popup window to select a custom
1384 * selection of groups/pairs
1385 */
1386void MuonFitPropertyBrowser::genGroupWindow() {
1387 // reset group window
1388 m_groupWindow = new QDialog(this);
1389 QtGroupPropertyManager *groupManager = new QtGroupPropertyManager(m_groupWindow);
1390 QVBoxLayout *layout = new QVBoxLayout(m_groupWindow);
1391 auto *groupBrowser = new QtTreePropertyBrowser();
1392 QtProperty *groupSettings = groupManager->addProperty("Group/Pair selection");
1393 for (auto iter = m_groupBoxes.constBegin(); iter != m_groupBoxes.constEnd(); ++iter) {
1394 groupSettings->addSubProperty(m_groupBoxes.value(iter.key()));
1395 m_boolManager->setValue(iter.value(), m_boolManager->value(iter.value()));
1396 }
1397 QtCheckBoxFactory *checkBoxFactory = new QtCheckBoxFactory(m_groupWindow);
1398 groupBrowser->setFactoryForManager(m_boolManager, checkBoxFactory);
1399 groupBrowser->addProperty(groupSettings);
1400 layout->addWidget(groupBrowser);
1401 m_groupWindow->setLayout(layout);
1402 m_groupWindow->show();
1403}
1407void MuonFitPropertyBrowser::setAllPeriods() {
1408
1409 for (auto iter = m_periodBoxes.constBegin(); iter != m_periodBoxes.constEnd(); ++iter) {
1410 m_boolManager->setValue(iter.value(), true);
1411 }
1412}
1413
1418void MuonFitPropertyBrowser::setNumPeriods(size_t numPeriods) {
1419 // delete period checkboxes
1420 clearPeriodCheckboxes();
1421 if (!m_periodsToFitOptions.empty()) {
1422 m_periodsToFitOptions.clear();
1423 }
1424
1425 if (numPeriods > 1) {
1426 m_periodsToFitOptions << ALL_PERIODS_LABEL;
1427 m_periodsToFitOptions << CUSTOM_LABEL;
1428 }
1429
1430 // create more boxes
1431 for (size_t i = 0; i != numPeriods; i++) {
1432 QString name = QString::number(i + 1);
1433 addPeriodCheckbox(name);
1434 }
1435
1436 if (m_periodsToFitOptions.size() == 1) {
1437 m_generateBtn->setDisabled(true);
1438 m_multiFitSettingsGroup->property()->removeSubProperty(m_periodsToFit);
1439 m_multiFitSettingsGroup->property()->removeSubProperty(m_showPeriods);
1440 m_enumManager->setValue(m_periodsToFit, 0);
1441 clearChosenPeriods();
1442 m_boolManager->setValue(m_periodBoxes.constBegin().value(), true);
1443 } else {
1444 // for now always reset to all groups when data is changed
1445 // the commented out code can be used to keep the selection when changing
1446 // run - but has a bug
1447 m_multiFitSettingsGroup->property()->insertSubProperty(m_periodsToFit, m_showGroup);
1448 m_multiFitSettingsGroup->property()->addSubProperty(m_showPeriods);
1449 m_generateBtn->setDisabled(false);
1450
1451 updatePeriods(0);
1452 }
1453}
1459void MuonFitPropertyBrowser::setAvailablePeriods(const QStringList &periods) {
1460 // If it's the same list, do nothing
1461 if (periods.size() == m_periodBoxes.size()) {
1462 auto existingGroups = m_periodBoxes.keys();
1463 auto newGroups = periods;
1464 qSort(existingGroups);
1465 qSort(newGroups);
1466 if (existingGroups == newGroups) {
1467 return;
1468 }
1469 }
1470
1471 clearPeriodCheckboxes();
1472
1473 for (const auto &group : periods) {
1474 addPeriodCheckbox(group);
1475 }
1476}
1481void MuonFitPropertyBrowser::clearPeriodCheckboxes() {
1482 if (m_periodBoxes.size() > 1) {
1483 for (auto iter = std::next(m_periodBoxes.constBegin()); iter != m_periodBoxes.constEnd(); ++iter) {
1484 delete (*iter);
1485 }
1486 m_periodBoxes.clear();
1487 }
1488 m_periodsToFitOptions.clear();
1489 m_periodsToFitOptions << "1";
1490 m_enumManager->setEnumNames(m_periodsToFit, m_periodsToFitOptions);
1491}
1495void MuonFitPropertyBrowser::clearChosenPeriods() const {
1496 for (auto iter = m_periodBoxes.constBegin(); iter != m_periodBoxes.constEnd(); ++iter) {
1497 m_boolManager->setValue(iter.value(), false);
1498 }
1499}
1503void MuonFitPropertyBrowser::updatePeriods() {
1504 int j = m_enumManager->value(m_periodsToFit);
1505 // auto selected = getChosenPeriods();
1506 updatePeriods(j);
1507}
1516void MuonFitPropertyBrowser::updatePeriods(const int j) {
1517 // this is for switching but has a bug at the moment
1518 // const QStringList &selected) {
1519 if (m_periodsToFitOptions.size() == 0) {
1520 QMessageBox::warning(this, "Muon Analysis",
1521 "Data not found. Please turn on the data archive, "
1522 "using the Manage Directories button.");
1523 return;
1524 }
1525 m_enumManager->setEnumNames(m_periodsToFit, m_periodsToFitOptions);
1526 m_enumManager->setValue(m_periodsToFit, j);
1527 if (m_periodsToFitOptions[j] == CUSTOM_LABEL) {
1528 // currently the below does not work reliably (if period arithmatic is
1529 // presemnt it gives bad results
1530 /*
1531 setChosenPeriods(selected);*/
1532 // lets default to all periods for now
1533 // explictly set all periods
1534 setAllPeriods();
1535 } else if (m_periodsToFitOptions[j] == ALL_PERIODS_LABEL) {
1536 // explictly set all periods
1537 setAllPeriods();
1538 } else { // single number
1539 setChosenPeriods(m_periodsToFitOptions[j]);
1540 }
1541}
1547void MuonFitPropertyBrowser::addPeriodCheckboxToMap(const QString &name) {
1548 if (m_periodBoxes.find(name) != m_periodBoxes.end()) {
1549 // if the box already exists
1550 return;
1551 }
1552 // has to go here to get the original value
1553 int j = m_enumManager->value(m_periodsToFit);
1554 // auto selected = getChosenPeriods();
1555 addPeriodCheckbox(name);
1556 updatePeriods(j);
1557}
1562bool MuonFitPropertyBrowser::isPeriodValid(const QString &name) {
1563 // check period is sensible
1564 // no frational periods
1565 if (name.contains(".")) {
1566 return false;
1567 }
1568 // wshould only ever have 1 minus sign
1569 else if (name.count("-") > 1) {
1570 return false;
1571 } else {
1572 std::vector<std::string> numbers;
1573 std::string nameString = name.toStdString();
1574 boost::algorithm::split(numbers, nameString, boost::is_any_of(","));
1575 // loop over results
1576 for (auto value : numbers) {
1577 auto tmp = value.find("-");
1578 if (tmp != std::string::npos) {
1579 // find a minus sign
1580 auto before = value.substr(0, tmp);
1581 auto after = value.substr(tmp + 1);
1582
1583 } else {
1584 try {
1585 boost::lexical_cast<int>(value);
1586 if (m_periodBoxes.find(QString::fromStdString(value)) == m_periodBoxes.end() && numbers.size() > 1) {
1587 // if the box does not exist and there is more than 1 period in name
1588 return false;
1589 }
1590 } catch (const boost::bad_lexical_cast &) {
1591 // none int value
1592 return false;
1593 }
1594 }
1595 }
1596 }
1597 return true;
1598}
1604void MuonFitPropertyBrowser::addPeriodCheckbox(const QString &name) {
1605 // check period is sensible
1606 // no frational periods
1607 if (isPeriodValid(name)) {
1608 m_periodBoxes.insert(name, m_boolManager->addProperty(name));
1609 int j = m_enumManager->value(m_periodsToFit);
1610 // add new period to list will go after inital list
1611 m_periodsToFitOptions << name;
1612
1613 auto active = getChosenPeriods();
1614 m_enumManager->setEnumNames(m_periodsToFit, m_periodsToFitOptions);
1615 setChosenPeriods(active);
1616 m_enumManager->setValue(m_periodsToFit, j);
1617 }
1618}
1623QStringList MuonFitPropertyBrowser::getChosenPeriods() const {
1624 QStringList chosen;
1625 // if single period
1626 if (m_periodsToFitOptions.size() == 1) {
1627 chosen << "";
1628 } else {
1629 for (auto iter = m_periodBoxes.constBegin(); iter != m_periodBoxes.constEnd(); ++iter) {
1630 if (m_boolManager->value(iter.value()) == true) {
1631 chosen.append(iter.key());
1632 }
1633 }
1634 }
1635 return chosen;
1636}
1641void MuonFitPropertyBrowser::setChosenPeriods(const QStringList &chosenPeriods) {
1642 clearChosenPeriods();
1643 for (const auto &selected : chosenPeriods) {
1644 for (auto iter = m_periodBoxes.constBegin(); iter != m_periodBoxes.constEnd(); ++iter) {
1645 if (iter.key() == selected) {
1646 m_boolManager->setValue(iter.value(), true);
1647 }
1648 }
1649 }
1650}
1655void MuonFitPropertyBrowser::setChosenPeriods(const QString &period) {
1656 clearChosenPeriods();
1657 for (auto iter = m_periodBoxes.constBegin(); iter != m_periodBoxes.constEnd(); ++iter) {
1658 if (iter.key() == period) {
1659 m_boolManager->setValue(iter.value(), true);
1660 }
1661 }
1662}
1663/*
1664 * Create a pop up window to select a custom
1665 * selection of periods
1666 */
1667void MuonFitPropertyBrowser::genPeriodWindow() {
1668 // reset period window
1669 m_periodWindow = new QDialog(this);
1670 QtGroupPropertyManager *groupManager = new QtGroupPropertyManager(m_periodWindow);
1671 QVBoxLayout *layout = new QVBoxLayout(m_periodWindow);
1672 auto *groupBrowser = new QtTreePropertyBrowser();
1673 QtProperty *groupSettings = groupManager->addProperty("Period selection");
1674 for (auto iter = m_periodBoxes.constBegin(); iter != m_periodBoxes.constEnd(); ++iter) {
1675 groupSettings->addSubProperty(m_periodBoxes.value(iter.key()));
1676 m_boolManager->setValue(iter.value(), m_boolManager->value(iter.value()));
1677 }
1678 QtCheckBoxFactory *checkBoxFactory = new QtCheckBoxFactory(m_periodWindow);
1679 groupBrowser->setFactoryForManager(m_boolManager, checkBoxFactory);
1680 groupBrowser->addProperty(groupSettings);
1681 layout->addWidget(groupBrowser);
1682 m_periodWindow->setLayout(layout);
1683 m_periodWindow->show();
1684}
1685/*
1686 * Create a pop up window to create
1687 * a combination of periods
1688 */
1689void MuonFitPropertyBrowser::genCombinePeriodWindow() {
1690 // reset combine window
1691 m_comboWindow = new QDialog(this);
1692 QVBoxLayout *layout = new QVBoxLayout(m_comboWindow);
1693 auto *formLayout = new QFormLayout;
1694 m_positiveCombo = new QLineEdit();
1695 m_negativeCombo = new QLineEdit();
1696 formLayout->addRow(new QLabel(tr("Combine:")), m_positiveCombo);
1697 formLayout->addRow(new QLabel(tr(" - ")), m_negativeCombo);
1698 layout->addLayout(formLayout);
1699
1700 auto *applyBtn = new QPushButton("Apply");
1701
1702 connect(applyBtn, SIGNAL(released()), this, SLOT(combineBtnPressed()));
1703
1704 layout->addWidget(applyBtn);
1705 m_comboWindow->setLayout(layout);
1706 m_comboWindow->show();
1707}
1708/*
1709 * Get the positive and negative parts of the
1710 * combination of periods and produce a new
1711 * tick box. Unticked by default.
1712 */
1713void MuonFitPropertyBrowser::combineBtnPressed() {
1714 QString value = m_positiveCombo->text();
1715 if (value.isEmpty()) {
1716 g_log.error("There are no positive periods (top box)");
1717 return;
1718 }
1719 if (!m_negativeCombo->text().isEmpty()) {
1720 value.append("-").append(m_negativeCombo->text());
1721 }
1722 m_positiveCombo->clear();
1723 m_negativeCombo->clear();
1724 addPeriodCheckbox(value);
1725 int j = m_enumManager->value(m_periodsToFit);
1726 if (m_periodsToFitOptions[j] == ALL_PERIODS_LABEL) {
1727 setAllPeriods();
1728 }
1729}
1735void MuonFitPropertyBrowser::setSingleFitLabel(const std::string &name) {
1736 clearChosenGroups();
1737 clearChosenPeriods();
1738 std::vector<std::string> splitName;
1739 std::string tmpName = name;
1740 boost::erase_all(tmpName, " ");
1741 boost::split(splitName, tmpName, boost::is_any_of(";"));
1742 // set single group/pair
1743 QString group = QString::fromUtf8(splitName[2].c_str());
1744 setChosenGroup(group);
1745 // set period if available
1746 if (splitName.size() == 6) {
1747 QString period = QString::fromUtf8(splitName[4].c_str());
1748 setChosenPeriods(period);
1749 }
1750 setOutputName(name);
1751 // for single fit in multi fit mode
1752 if (m_browser->isItemVisible(m_multiFitSettingsGroup)) {
1753 updateGroupDisplay();
1754 updatePeriodDisplay();
1755 }
1756}
1763void MuonFitPropertyBrowser::setAllGroupsOrPairs(const bool isItGroup) {
1764
1765 auto index = m_enumManager->value(m_groupsToFit);
1766 QString name = m_groupsToFitOptions[index];
1767 if (name == CUSTOM_LABEL) {
1768 auto vals = getChosenGroups();
1769 clearChosenGroups();
1770 for (const auto &group : vals) {
1771
1772 for (auto iter = m_groupBoxes.constBegin(); iter != m_groupBoxes.constEnd(); ++iter) {
1773 if (iter.key().toStdString() == group.toStdString()) {
1774 m_boolManager->setValue(iter.value(), true);
1775 }
1776 }
1777 }
1778 } else if (name == ALL_GROUPS_LABEL) {
1779 m_enumManager->setValue(m_groupsToFit, 0);
1780 setAllGroups();
1781 if (getChosenGroups().size() > 0) {
1782 return;
1783 }
1784 } else if (name == ALL_PAIRS_LABEL) { // all pairs is index 1
1785 m_enumManager->setValue(m_groupsToFit, 1);
1786 setAllPairs();
1787 }
1788 if (getChosenGroups().size() > 0) {
1789 return;
1790 } else {
1791
1792 if (isItGroup) {
1793 // all groups is index 0
1794 m_enumManager->setValue(m_groupsToFit, 0);
1795 setAllGroups();
1796 } else {
1797 // all pairs is index 1
1798 m_enumManager->setValue(m_groupsToFit, 1);
1799 setAllPairs();
1800 }
1801 }
1802}
1803void MuonFitPropertyBrowser::setGroupNames(std::vector<std::string> groupNames) {
1804 m_groupsList = std::move(groupNames);
1805}
1806void MuonFitPropertyBrowser::setTFAsymm(bool state) { m_boolManager->setValue(m_TFAsymmMode, state); }
1807
1808} // namespace MantidWidgets
1809} // namespace MantidQt
gsl_vector * tmp
double value
The value of the point.
Definition: FitMW.cpp:51
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
void observeFinish(AlgorithmObserver &self, const boost::python::object &alg)
Class FitPropertyBrowser implements QtPropertyBrowser to display and control fitting function paramet...
bool rawData() const override
Returns true if the fit should be done against binned (bunched) data.
void setOutputName(const std::string &)
Set the output name.
void updateDecimals()
impose a number of decimal places on all defined Double properties
std::shared_ptr< Mantid::API::CompositeFunction > compositeFunction() const
Get Composite Function.
virtual void boolChanged(QtProperty *prop)
Called when a bool property is changed.
virtual void enumChanged(QtProperty *prop)
Called when the function name property changed.
void setWorkspace(const Mantid::API::IFunction_sptr &function) const
Sets the workspace to a function.
std::string workspaceName() const
Get the input workspace name.
QStringList m_registeredBackgrounds
A list of registered backgrounds.
QStringList m_registeredOther
A list of registered functions that are neither peaks nor backgrounds.
void createEditors(QWidget *w)
Create editors and assign them to the managers.
std::vector< double > m_initialParameters
To keep a copy of the initial parameters in case for undo fit.
QtGroupPropertyManager * m_groupManager
Property managers:
QStringList m_registeredPeaks
A list of registered peaks.
void updateStructureTooltips()
Update structure tooltips for all functions.
void initBasicLayout(QWidget *w)
Initialise the layout, except for the fit button in the menu bar.
QtBrowserItem * m_settingsGroup
Group for input/output settings.
QStringList m_workspaceNames
A list of available workspaces.
std::string minimizer(bool withProperties=false) const
Get the minimizer.
bool m_changeSlotsEnabled
If false the change-slots (such as enumChanged(), doubleChanged()) are disabled.
QtBrowserItem * m_functionsGroup
Group for functions.
PropertyHandler * getHandler() const
Get handler to the root composite function.
QStringList m_evaluationTypes
A list of possible function evaluation types.
bool plotDiff() const
Returns true if the difference plot should be drawn.
QStringList m_minimizers
A list of available minimizers.
QStringList m_registeredFunctions
A list of registered functions.
void populateWorkspaceNames()
Get and store available workspace names.
QtProperty * addDoubleProperty(const QString &name, QtDoublePropertyManager *manager=nullptr) const
Create a double property and set some settings.
std::shared_ptr< Mantid::API::CompositeFunction > m_compositeFunction
A copy of the edited function.
QStringList m_costFunctions
A list of available cost functions.
QtBrowserItem * m_customSettingsGroup
Group for custom options available on muon analysis widget.
Class FitPropertyBrowser implements QtPropertyBrowser to display and control fitting function paramet...
IFunction_sptr getGlobalFunction() override
Return the multidomain function if number of datasets is greater than 1.
void boolChanged(QtProperty *prop) override
Called when a bool property changed.
void doubleChanged(QtProperty *prop) override
Called when a double property changed.
void updateGroupDisplay()
Sets the display for selected groups.
QStringList getChosenGroups() const
Returns a list of the selected groups (checked boxes)
QMap< QString, QtProperty * > m_periodBoxes
Map of group names to checkboxes.
void populateFunctionNames() override
Get the registered function names.
void fitRawDataClicked(bool enabled) override
Emitted when "fit to raw data" is changed.
void clearChosenGroups() const
Clear list of selected groups.
std::string getUnnormName(const std::string wsName)
virtual void setFitEnabled(bool yes) override
Enable/disable the Fit button;.
void updateTFPlot()
Makes sure we have the TF plot in TFAsymm mode.
QSplitter * m_widgetSplitter
Splitter for additional widgets and splitter between this and browser.
MantidQt::MantidWidgets::FunctionBrowser * m_functionBrowser
void setSingleFitLabel(const std::string &name)
sets the label for a single fit and selects the relevant group/pair
QStringList getChosenPeriods() const
Returns a list of the selected periods (checked boxes)
void setTFAsymmMode(bool state)
Set TF asymmetry mode on or off.
QMap< QString, QtProperty * > m_groupBoxes
Map of group names to checkboxes.
std::string outputName() const override
Get output name.
static const std::string SIMULTANEOUS_PREFIX
Prefix for simultaneous fit results.
void doTFAsymmFit()
Creates an instance of Fit algorithm, sets its properties and launches it.
void enumChanged(QtProperty *prop) override
Called when a dropdown menu is changed.
std::vector< std::string > m_workspacesToFit
Names of workspaces to fit.
void addGroupCheckbox(const QString &name)
Add a new checkbox to the list of groups with given name The new checkbox is checked according to dro...
void setWorkspaceName(const QString &wsName) override
Set the input workspace name.
void updatePeriodDisplay()
Sets the display for selected periods.
MuonFitPropertyBrowser(QWidget *parent=nullptr, QObject *mantidui=nullptr)
Constructor.
Helps display and edit functions in FitPropertyBrowser.
bool setAttribute(QtProperty *prop, bool resetProperties=true)
Set function attribute value read from a QtProperty.
void addConstraint(QtProperty *parProp, bool lo, bool up, double loBound, double upBound)
Add constraint to parameter property parProp.
PropertyHandler * findHandler(const Mantid::API::IFunction *fun)
QtProperty * getParameterProperty(const QString &parName) const
void observeFinish(const IAlgorithm_const_sptr &alg)
Connect to algorithm alg and observe its finish notification.
The Analysis data service stores instances of the Workspace objects and anything that derives from te...
void addOrReplace(const std::string &name, const std::shared_ptr< API::Workspace > &workspace) override
Overridden addOrReplace member to attach the name to the workspace when a workspace object is added t...
void addToGroup(const std::string &groupName, const std::string &wsName)
Add a workspace to a group.
std::shared_ptr< WSTYPE > retrieveWS(const std::string &name) const
Retrieve a workspace and cast it to the given WSTYPE.
void copyExperimentInfoFrom(const ExperimentInfo *other)
Copy everything from the given experiment object.
IAlgorithm is the interface implemented by the Algorithm base class.
Definition: IAlgorithm.h:45
virtual const std::string name() const =0
function to return a name of the algorithm, must be overridden in all algorithms
An interface to a background function.
An interface to a peak function, which extend the interface of IFunctionWithLocation by adding method...
Definition: IPeakFunction.h:51
ITableWorkspace is an implementation of Workspace in which the data are organised in columns of same ...
Base MatrixWorkspace Abstract Class.
TableRow represents a row in a TableWorkspace.
Definition: TableRow.h:39
Class to hold a set of workspaces.
Exception for when an item is not found in a collection.
Definition: Exception.h:145
const char * what() const noexcept override
Writes out the range and limits.
Definition: Exception.cpp:105
virtual TypedValue getProperty(const std::string &name) const =0
Get the value of a property.
virtual std::string getPropertyValue(const std::string &name) const =0
Get the value of a property as a string.
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition: Logger.h:52
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
std::map< std::string, double > readMultipleNormalization()
Reads the normalization constants and which WS they belong to.
The AlgorithmProgressDialogPresenter keeps track of the running algorithms and displays a progress ba...
std::shared_ptr< IAlgorithm > IAlgorithm_sptr
shared pointer to Mantid::API::IAlgorithm
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Definition: Workspace_fwd.h:20
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
Definition: IFunction.h:732