Skip to content
Snippets Groups Projects
FitPropertyBrowser.cpp 106 KiB
Newer Older
/**
 * Slot. Ties a parameter to a parameter with the same name of a different
 * function
void FitPropertyBrowser::addTieToFunction() {
  QtBrowserItem *ci = m_browser->currentItem();
  QtProperty *paramProp = ci->property();
  PropertyHandler *h = getHandler()->findHandler(paramProp);
  if (!h)
    return;
  if (!h->isParameter(paramProp))
    return;
  std::string parName = paramProp->propertyName().toStdString();
  QStringList fnNames;

  int iPar = -1;
  for (size_t i = 0; i < m_compositeFunction->nParams(); i++) {
    Mantid::API::ParameterReference ref(m_compositeFunction.get(), i);
    Mantid::API::IFunction *fun = ref.getLocalFunction();
    // Pick out parameters with the same name as the one we're tying from
    if (fun->parameterName(static_cast<int>(ref.getLocalIndex())) == parName) {
      if (iPar == -1 &&
          fun ==
              h->function()
                  .get()) // If this is the 'tied from' parameter, remember it
        iPar = (int)i;
      } else // Otherwise add it to the list of potential 'tyees'
        fnNames << QString::fromStdString(
            m_compositeFunction->parameterName(i));
  if (fnNames.empty() || iPar < 0) {
    QMessageBox::information(this, "Mantid - information",
                             "Cannot tie this parameter to any function");
  QString tieName = QInputDialog::getItem(
      this, "MantidPlot - Fit", "Select function", fnNames, 0, false, &ok);
  QString tieExpr =
      QString::fromStdString(m_compositeFunction->parameterName(iPar)) + "=" +
      tieName;

  h->addTie(tieExpr);
}

 * Slot. Adds a tie. The current item must be a function parameter
 */
void FitPropertyBrowser::addFixTie() {
  QtBrowserItem *ci = m_browser->currentItem();
  QtProperty *paramProp = ci->property();
  PropertyHandler *h = getHandler()->findHandler(paramProp);
  if (!h)
    return;
  if (!h->isParameter(paramProp))
    return;
  h->fix(paramProp->propertyName());
}

void FitPropertyBrowser::deleteTie() {
  QtBrowserItem *ci = m_browser->currentItem();
  QtProperty *paramProp = ci->property();
  PropertyHandler *h = getHandler()->findHandler(paramProp);
  if (!h)
    return;
  // get name of parent property (i.e. function)
  if (paramProp->propertyName() != "Tie") {
    auto parameterMap = h->getTies();
    auto match = parameterMap.find(paramProp->propertyName());
    if (match != parameterMap.end()) {
      paramProp = match.value();
    }
  }
  if (paramProp->propertyName() == "Tie") {
    auto ties = h->getTies();
    QString qParName = ties.key(paramProp, "");
    std::string parName = qParName.toStdString();
    QStringList functionNames;
    // ithParameter = -1 => not found
    int ithParameter = -1;
    for (size_t i = 0; i < m_compositeFunction->nParams(); i++) {
      Mantid::API::ParameterReference parameterRef(m_compositeFunction.get(),
                                                   i);
      Mantid::API::IFunction *function = parameterRef.getLocalFunction();
      // Pick out parameters with the same name as the one we're tying from
      if (function->parameterName(
              static_cast<int>(parameterRef.getLocalIndex())) == parName) {
        if (ithParameter == -1 &&
            function ==
                h->function()
                    .get()) // If this is the 'tied from' parameter, remember it
        {
          ithParameter = static_cast<int>(i);
        } else // Otherwise add it to the list of potential 'tyees'
        {
          functionNames << QString::fromStdString(
              m_compositeFunction->parameterName(i));
        }
      }
    }
    if (functionNames.empty() && ithParameter < 0) {
      QMessageBox::information(this, "Mantid - information",
                               "Cannot find a parameter with this tie");
    } else {
      QString tieExpr = QString::fromStdString(
          m_compositeFunction->parameterName(ithParameter));
      h->removeTie(paramProp, tieExpr.toStdString());
    }
  } else {
    h->removeTie(ci->property()->propertyName());
  }
}

/** Does a parameter have a tie
 * @param parProp :: The property for a function parameter
 * @param hasTie :: Parameter has a tie
 * @param hasBounds :: Parameter has bounds
void FitPropertyBrowser::hasConstraints(QtProperty *parProp, bool &hasTie,
                                        bool &hasBounds) const {
  hasTie = false;
  hasBounds = false;
  QList<QtProperty *> subs = parProp->subProperties();
  for (int i = 0; i < subs.size(); i++) {
    if (subs[i]->propertyName() == "Tie") {
      hasTie = true;
    }
    if (subs[i]->propertyName() == "LowerBound") {
      hasBounds = true;
    }
    if (subs[i]->propertyName() == "UpperBound") {
/** Returns the tie property for a parameter property, or nullptr
 * @param parProp :: parameter property
QtProperty *FitPropertyBrowser::getTieProperty(QtProperty *parProp) const {
  QList<QtProperty *> subs = parProp->subProperties();
  for (int i = 0; i < subs.size(); i++) {
    if (subs[i]->propertyName() == "Tie") {
      return subs[i];
    }
  }
/**
 * Called when the function factory has been updated
 * @param notice A Poco notification object
 */
void FitPropertyBrowser::handleFactoryUpdate(
    Mantid::API::FunctionFactoryUpdateNotification_ptr notice) {
  // Don't call populate directly as the updates can come from a different
  // thread
  emit functionFactoryUpdateReceived();
}

/** Display a tip
 * @param txt :: The text to display
 */
void FitPropertyBrowser::setTip(const QString &txt) { m_tip->setText(txt); }

/**
 * Slot. Adds lower bound to the selected parameter property
 * and sets it f % below parameter's current value
 */
void FitPropertyBrowser::addConstraint(int f, bool lo, bool up) {
  QtBrowserItem *ci = m_browser->currentItem();
  QtProperty *parProp = ci->property();
  PropertyHandler *h = getHandler()->findHandler(parProp);
  if (!h)
    return;

  double x = m_doubleManager->value(parProp);
  double loBound = x * (1 - 0.01 * f);
  double upBound = x * (1 + 0.01 * f);
  h->addConstraint(ci->property(), lo, up, loBound, upBound);
}

/**
 * Slot. Adds lower bound to the selected parameter property
 */
void FitPropertyBrowser::addLowerBound() { addConstraint(0, true, false); }

/**
 * Slot. Adds lower bound to the selected parameter property
 */
void FitPropertyBrowser::addLowerBound10() { addConstraint(10, true, false); }

/**
 * Slot. Adds lower bound to the selected parameter property
 */
void FitPropertyBrowser::addLowerBound50() { addConstraint(50, true, false); }

/**
 * Slot.Adds upper bound to the selected parameter property
 */
void FitPropertyBrowser::addUpperBound10() { addConstraint(10, false, true); }

/**
 * Slot.Adds upper bound to the selected parameter property
 */
void FitPropertyBrowser::addUpperBound50() { addConstraint(50, false, true); }

/**
 * Slot.Adds upper bound to the selected parameter property
 */
void FitPropertyBrowser::addUpperBound() { addConstraint(0, false, true); }
 * Slot.Sets the lower and upper bounds of the selected parameter to 10% of its
 * value
void FitPropertyBrowser::addBothBounds10() { addConstraint(10, true, true); }
 * Slot.Sets the lower and upper bounds of the selected parameter to 50% of its
 * value
void FitPropertyBrowser::addBothBounds50() { addConstraint(50, true, true); }

/**
 * Slot.Adds lower and upper bounds to the selected parameter property
 */
void FitPropertyBrowser::addBothBounds() { addConstraint(0, true, true); }

/**
 * Slot.Removes lower and upper bounds from the selected parameter property
 */
void FitPropertyBrowser::removeBounds() {
  QtBrowserItem *ci = m_browser->currentItem();
  QtProperty *parProp = ci->property();
  PropertyHandler *h = getHandler()->findHandler(parProp);
  if (!h)
    return;

  h->removeConstraint(parProp);
}

/**
 * Slot. Sends a signal to plot the guess for the current (selected) function
 */
void FitPropertyBrowser::plotGuessCurrent() { emit plotCurrentGuess(); }

/**
 * Slot. Sends a signal to plot the guess for the whole function
 */
void FitPropertyBrowser::plotGuessAll() { emit plotGuess(); }

/**
 * Slot. Sends a signal to remove the guess for the current (selected) function
 */
void FitPropertyBrowser::removeGuessCurrent() { emit removeCurrentGuess(); }

/**
 * Slot. Sends a signal to remove the guess for the whole function
 */
void FitPropertyBrowser::removeGuessAll() { emit removeGuess(); }
void FitPropertyBrowser::plotOrRemoveGuessAll() {
  if (getHandler()->hasPlot()) {
    removeGuessAll();
void FitPropertyBrowser::clearAllPlots() { emit removeFitCurves(); }
/** Create a double property and set some settings
 * @param name :: The name of the new property
 * @param manager :: The current property manager
 * @return Pointer to the created property
 */
QtProperty *
FitPropertyBrowser::addDoubleProperty(const QString &name,
                                      QtDoublePropertyManager *manager) const {
  if (manager == nullptr)
    manager = m_doubleManager;
  QtProperty *prop = manager->addProperty(name);
  manager->setDecimals(prop, m_decimals);
  manager->setRange(prop, -DBL_MAX, DBL_MAX);
  return prop;
}

/** Create a string property and selects a property manager for it
 * based on the property name
 * @param name :: The name of the new property
 * @return Pointer to the created property
 */
QtProperty *FitPropertyBrowser::addStringProperty(const QString &name) const {
  QtProperty *prop;
  QString propName = name.toLower();
  if (propName == "filename") {
    prop = m_filenameManager->addProperty(name);
  } else if (propName == "formula") {
    //!!! dont forget to change the manager !!!
    prop = m_formulaManager->addProperty(name);
    prop = m_stringManager->addProperty(name);
  }
  return prop;
}

/**
 * Set a value to a string property.
 * @param prop :: A pointer to the property
 * @param value :: New value for the property
 */
void FitPropertyBrowser::setStringPropertyValue(QtProperty *prop,
                                                const QString &value) const {
  QtStringPropertyManager *manager =
      dynamic_cast<QtStringPropertyManager *>(prop->propertyManager());
  if (manager) {
    manager->setValue(prop, value);
QString FitPropertyBrowser::getStringPropertyValue(QtProperty *prop) const {
  QtStringPropertyManager *manager =
      dynamic_cast<QtStringPropertyManager *>(prop->propertyManager());
  if (manager)
    return manager->value(prop);
  else
    return QString("");
}

Mantid::API::IFunction_const_sptr FitPropertyBrowser::theFunction() const {
  return m_compositeFunction;
void FitPropertyBrowser::checkFunction() {}
void FitPropertyBrowser::saveFunction() {
  QString fnName = QInputDialog::getText(
      this, tr("Mantid - Input"), tr("Please select a name for the function"),
      QLineEdit::Normal, "", &ok);
  if (ok && !fnName.isEmpty()) {
void FitPropertyBrowser::saveFunction(const QString &fnName) {
  QSettings settings;
  settings.beginGroup("Mantid/FitBrowser/SavedFunctions");
  QStringList names = settings.childKeys();
  if (names.contains(fnName) &&
      QMessageBox::question(this, "Mantid - Question",
                            "Function with this name already exists.\n"
                            "Would you like to replace it?",
                            QMessageBox::Yes) != QMessageBox::Yes) {
  settings.setValue(fnName, QString::fromStdString(theFunction()->asString()));
  updateSetupMenus();
void FitPropertyBrowser::loadFunction() {
  QSettings settings;
  settings.beginGroup("Mantid/FitBrowser/SavedFunctions");
  QStringList names = settings.childKeys();
  if (names.isEmpty()) {
    QMessageBox::information(this, "Mantid - Information",
                             "There are no saved functions");
  QString name = QInputDialog::getItem(this, "Mantid - Input",
                                       "Please select a function to load",
                                       names, 0, false);
  if (!name.isEmpty()) {
    QString str = settings.value(name).toString();
    loadFunction(str);
void FitPropertyBrowser::loadFunctionFromString() {
  QString str = QInputDialog::getText(this, "Mantid - Input",
                                      "Specify fit function string");
void FitPropertyBrowser::loadFunction(const QString &funcString) {
  // when loading a function from a string initially
  // do not try to do auto background even if set
  getHandler()->removeAllPlots();
  clearBrowser();
  createCompositeFunction(funcString);
  emit functionLoaded(funcString);
void FitPropertyBrowser::copy() {
  QClipboard *clipboard = QApplication::clipboard();
  clipboard->setText(QString::fromStdString(theFunction()->asString()));
void FitPropertyBrowser::paste() {
  QClipboard *clipboard = QApplication::clipboard();
  QString str = clipboard->text();
  createCompositeFunction(str);
}

void FitPropertyBrowser::reset() {
  QString str = QString::fromStdString(theFunction()->asString());
  // getHandler()->removeAllPlots();// this crashes mantidplot
  clearBrowser();
  createCompositeFunction(str);
}

void FitPropertyBrowser::setWorkspace(Mantid::API::IFunction_sptr f) const {
  std::string wsName = workspaceName();
      auto ws = Mantid::API::AnalysisDataService::Instance().retrieve(wsName);
      auto mws = boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(ws);
      if (mws) {
        f->setMatrixWorkspace(mws, workspaceIndex(), startX(), endX());
      } else {
        f->setWorkspace(ws);
void FitPropertyBrowser::addAutoBackground() {
  if (m_autoBgName.isEmpty())
    return;
  bool hasPlot = false;
  PropertyHandler *ch = currentHandler();
  if (m_autoBackground) { // remove old background
    if (ch == m_autoBackground) {
    }
    hasPlot = m_autoBackground->hasPlot();
    m_autoBackground->removeFunction();
    m_autoBackground = nullptr;
  }
  // Create the function
  PropertyHandler *h = getHandler()->addFunction(m_autoBgName.toStdString());
  if (!h)
    return;
  if (!m_autoBgAttributes.isEmpty()) { // set attributes
    QStringList attList = m_autoBgAttributes.split(' ');
    foreach (QString att, attList) {
      QStringList name_value = att.split('=');
      if (name_value.size() == 2) {
        QString name = name_value[0].trimmed();
        QString value = name_value[1].trimmed();
        if (h->function()->hasAttribute(name.toStdString())) {
          h->setAttribute(name, value);
        }
      }
    }
  }
  h->fit();
  m_autoBackground = h;
  getHandler()->calcBaseAll();
    setCurrentFunction(h);
    emit plotCurrentGuess();
      setCurrentFunction(ch);
    }
  }
}

void FitPropertyBrowser::refitAutoBackground() {
  if (m_autoBackground) {
    m_autoBackground->fit();
  }
}

/**
 * Remember a background function name to be used for creating auto-background
 * @param aName :: A name of the auto-background. The may be followed by
 * attributes as name=value pairs separated by spaces.
 */
void FitPropertyBrowser::setAutoBackgroundName(const QString &aName) {
  try {
    QStringList nameList = aName.split(' ');
    if (nameList.isEmpty())
      return;
    QString name = nameList[0];
    boost::shared_ptr<Mantid::API::IFunction> f =
        boost::shared_ptr<Mantid::API::IFunction>(
            Mantid::API::FunctionFactory::Instance().createFunction(
                name.toStdString()));
    m_auto_back = true;
    m_autoBgName = name;
    if (nameList.size() > 1) {
      nameList.removeFirst();
      m_autoBgAttributes = nameList.join(" ");
    }
    Mantid::Kernel::ConfigService::Instance().setString(
        "curvefitting.autoBackground", aName.toStdString());
  } catch (...) {
    m_auto_back = false;
  }
}

/// Set LogValue for PlotPeakByLogValue
void FitPropertyBrowser::setLogValue(const QString &lv) {
  if (isWorkspaceAGroup()) {
    // validateGroupMember();
    if (!m_logValue) {
      m_logValue = m_enumManager->addProperty("LogValue");
      m_settingsGroup->property()->addSubProperty(m_logValue);
    }
    m_logs.clear();
    m_logs << "";
    /* if (!m_groupMember.empty())
     {
       Mantid::API::MatrixWorkspace_sptr ws =
         boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(
         Mantid::API::AnalysisDataService::Instance().retrieve(m_groupMember)
         );
       if (ws)
       {
         const std::vector<Mantid::Kernel::Property*> logs =
     ws->run().getLogData();
         for(int i=0;i<static_cast<int>(logs.size()); ++i)
         {
           m_logs << QString::fromStdString(logs[i]->name());
         }
       }
     }*/
    m_enumManager->setEnumNames(m_logValue, m_logs);
    int i = m_logs.indexOf(lv);
    if (i < 0)
      i = 0;
    m_enumManager->setValue(m_logValue, i);
std::string FitPropertyBrowser::getLogValue() const {
  if (isWorkspaceAGroup() && m_logValue) {
    int i = m_enumManager->value(m_logValue);
    if (i < m_logs.size())
      return m_logs[i].toStdString();
  }
  return "";
}

/// Remove LogValue from the browser
void FitPropertyBrowser::removeLogValue() {
  if (isWorkspaceAGroup())
    return;
  m_settingsGroup->property()->removeSubProperty(m_logValue);
  m_logValue = nullptr;
void FitPropertyBrowser::sequentialFit() {
  if (workspaceName() == outputName()) {
    setOutputName(outputName() + "_res");
  }
  SequentialFitDialog *dlg = new SequentialFitDialog(this, m_mantidui);
  std::string wsName = workspaceName();
  if (!wsName.empty() &&
      dlg->addWorkspaces(QStringList(QString::fromStdString(wsName)))) {
void FitPropertyBrowser::findPeaks() {
  std::string wsName = workspaceName();
  if (wsName.empty()) {
    QMessageBox::critical(this, "Mantid - Error", "Workspace name is not set");
    return;
  }

  std::string peakListName = wsName + "_PeakList_tmp";

  int FWHM, Tolerance;
  QString setting = QString::fromStdString(
      Mantid::Kernel::ConfigService::Instance().getString(
          "curvefitting.findPeaksFWHM"));
  FWHM = setting.isEmpty() ? 7 : setting.toInt();

  setting = QString::fromStdString(
      Mantid::Kernel::ConfigService::Instance().getString(
          "curvefitting.findPeaksTolerance"));
  Tolerance = setting.isEmpty() ? 4 : setting.toInt();

  Mantid::API::IAlgorithm_sptr alg =
      Mantid::API::AlgorithmManager::Instance().create("FindPeaks");
  alg->initialize();
  alg->setPropertyValue("InputWorkspace", wsName);
  alg->setProperty("WorkspaceIndex", workspaceIndex());
  alg->setPropertyValue("PeaksList", peakListName);
  alg->setProperty("FWHM", FWHM);
  alg->setProperty("Tolerance", Tolerance);

  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));

  Mantid::API::MatrixWorkspace_sptr inputWS =
      boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(
          Mantid::API::AnalysisDataService::Instance().retrieve(
              workspaceName()));
    alg->execute();
    Mantid::API::ITableWorkspace_sptr ws =
        boost::dynamic_pointer_cast<Mantid::API::ITableWorkspace>(
            Mantid::API::AnalysisDataService::Instance().retrieve(
                peakListName));

    clear();
    Mantid::API::ColumnVector<double> centre = ws->getVector("centre");
    Mantid::API::ColumnVector<double> width = ws->getVector("width");
    Mantid::API::ColumnVector<double> height = ws->getVector("height");
    for (size_t i = 0; i < centre.size(); ++i) {
      if (centre[i] < startX() || centre[i] > endX())
        continue;
      auto f = boost::dynamic_pointer_cast<Mantid::API::IPeakFunction>(
          Mantid::API::FunctionFactory::Instance().createFunction(
              defaultPeakType()));
      if (!f)
        break;
      f->setMatrixWorkspace(inputWS, workspaceIndex(), startX(), endX());
      f->setCentre(centre[i]);
      f->setFwhm(width[i]);
      f->setHeight(height[i]);
    QApplication::restoreOverrideCursor();
    throw;
  }

  QApplication::restoreOverrideCursor();
void FitPropertyBrowser::setPeakToolOn(bool on) {
  m_peakToolOn = on;
  m_displayActionPlotGuess->setEnabled(on);
/**
 * @brief impose a number of decimal places on all defined Double properties
 */
void FitPropertyBrowser::updateDecimals() {
  if (m_decimals < 0) {
    QSettings settings;
    settings.beginGroup("Mantid/FitBrowser");
    m_decimals = settings.value("decimals", 6).toInt();
  }
  QSet<QtProperty *> props = m_doubleManager->properties();
  foreach (QtProperty *prop, props) {
    m_doubleManager->setDecimals(prop, m_decimals);
void FitPropertyBrowser::setDecimals(int d) {
  m_decimals = d;
  QSettings settings;
  settings.beginGroup("Mantid/FitBrowser");
  settings.setValue("decimals", d);
  updateDecimals();
}

bool FitPropertyBrowser::plotDiff() const {
  return m_boolManager->value(m_plotDiff);
}

/// @returns true if each function with a composite should also be plotted
bool FitPropertyBrowser::plotCompositeMembers() const {
  return m_boolManager->value(m_plotCompositeMembers);
}

bool FitPropertyBrowser::rawData() const {
void FitPropertyBrowser::setTextPlotGuess(const QString text) {
void FitPropertyBrowser::workspaceChange(const QString &wsName) {
  if (m_guessOutputName) {
    if (isWorkspaceAGroup()) {
      m_stringManager->setValue(
          m_output, QString::fromStdString(workspaceName() + "_params"));
    } else {
      m_stringManager->setValue(m_output,
                                QString::fromStdString(workspaceName()));
  if (isWorkspaceAGroup()) {
  emit workspaceNameChanged(wsName);
  emit wsChangePPAssign(wsName);
}

 * Returns the list of workspace names the fit property browser is working on
 */
QStringList FitPropertyBrowser::getWorkspaceNames() { return m_workspaceNames; }
/**
 * Call MultifitSetupDialog to populate MultiBG function.
 */
void FitPropertyBrowser::setupMultifit() {
  MultifitSetupDialog *dlg = new MultifitSetupDialog(this);
Doucet, Mathieu's avatar
Doucet, Mathieu committed
  dlg->exec();
  QStringList ties = dlg->getParameterTies();
    QString wsName = QString::fromStdString(workspaceName());
    Mantid::API::MatrixWorkspace_sptr mws =
        boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(
            Mantid::API::AnalysisDataService::Instance().retrieve(
                workspaceName()));
    if (mws) {
      auto fun = m_compositeFunction->getFunction(0);
      QString fun1Ini = QString::fromStdString(fun->asString());
      QString funIni = "composite=MultiBG;" + fun1Ini + ",Workspace=" + wsName +
                       ",WSParam=(WorkspaceIndex=0);";
      for (size_t i = 1; i < mws->getNumberHistograms(); ++i) {
        QString comma = i > 1 ? "," : "";
        QString fi = comma + "f" + QString::number(i) + ".";
        for (int j = 0; j < static_cast<int>(fun->nParams()); ++j) {
          if (!ties[j].isEmpty()) {
            tieStr += fi + QString::fromStdString(fun->parameterName(j)) + "=" +
                      ties[j];
        QString wsParam = ",WSParam=(WorkspaceIndex=" + QString::number(i);
        wsParam += ",StartX=" + QString::number(startX()) + ",EndX=" +
                   QString::number(endX()) + ")";
        funIni += fun1Ini + ",Workspace=" + wsName + wsParam + ";";
      if (!tieStr.isEmpty()) {
        funIni += "ties=(" + tieStr + ")";
      }
      loadFunction(funIni);
    }
  }
}

/// Process and create some output if it is a MultiBG fit
void FitPropertyBrowser::processMultiBGResults() {
  if (compositeFunction()->name() != "MultiBG")
    return;

  // if all member functions are of the same type and composition
  // create a TableWorkspace with parameter series

  // check if member functions are the same
  QStringList parNames;
  auto fun0 = compositeFunction()->getFunction(0);
  if (!fun0) {
    throw std::runtime_error(
        "IFunction expected but func function of another type");
  for (size_t i = 0; i < fun0->nParams(); ++i) {
    parNames << QString::fromStdString(fun0->parameterName(i));
  }

  for (size_t i = 1; i < compositeFunction()->nFunctions(); ++i) {
    auto fun = compositeFunction()->getFunction(i);
    if (!fun) {
      throw std::runtime_error(
          "IFunction expected but func function of another type");
    for (size_t j = 0; j < fun->nParams(); ++j) {
      if (parNames.indexOf(QString::fromStdString(fun->parameterName(j))) < 0) {
        // Functions are different, stop
        return;
      }
    }
  }

  QApplication::setOverrideCursor(Qt::WaitCursor);
  // create a TableWorkspace: first column - function index
  // other colomns - the parameters
  Mantid::API::ITableWorkspace_sptr table =
      Mantid::API::WorkspaceFactory::Instance().createTable("TableWorkspace");
  table->addColumn("int", "Index");
  foreach (QString par, parNames) {
    table->addColumn("double", par.toStdString());
  // Create WorkspaceGroup with the fit results
  std::vector<std::string> worspaceNames(compositeFunction()->nFunctions());
  for (size_t i = 0; i < compositeFunction()->nFunctions(); ++i) {
    // Mantid::API::TableRow row = table->appendRow();
    // row << int(i);
    // Mantid::API::IFunctionMW* fun =
    // dynamic_cast<Mantid::API::IFunctionMW*>(compositeFunction()->getFunction(i));
    // for(size_t j = 0; j < fun->nParams(); ++j)
    //{
    //  row << fun->getParameter(j);
    //}
    // size_t wi = fun->getWorkspaceIndex();
    // Mantid::API::MatrixWorkspace_sptr mws =
    // fun->createCalculatedWorkspace(fun->getMatrixWorkspace(),wi);
    // worspaceNames[i] =
    // workspaceName()+"_"+QString::number(wi).toStdString()+"_Workspace";
    // Mantid::API::AnalysisDataService::Instance().addOrReplace(worspaceNames[i],mws);
  Mantid::API::AnalysisDataService::Instance().addOrReplace(
      workspaceName() + "_Param_series", table);
  try {
    Mantid::API::IAlgorithm_sptr group =
        Mantid::API::AlgorithmManager::Instance().create("GroupWorkspaces");
    group->setProperty("InputWorkspaces", worspaceNames);
    group->setPropertyValue("OutputWorkspace", workspaceName() + "_Workspace");
  }
  QApplication::restoreOverrideCursor();
}

/**
 * Display properties relevant to the selected workspace:
 * WorkspaceIndex, StartX, and EndX for a MatrixWorkspace;
 * XColumn, YColumn, and ErrColumn for a TableWorkspace.
 */
void FitPropertyBrowser::setWorkspaceProperties() {
  if (m_browser->isItemVisible(m_settingsGroup)) {
    if (m_settingsGroup->property()->subProperties().contains(
            m_workspaceIndex)) {
      m_settingsGroup->property()->removeSubProperty(m_workspaceIndex);
    } else if (m_settingsGroup->property()->subProperties().contains(
                   m_xColumn)) {
      m_settingsGroup->property()->removeSubProperty(m_xColumn);
      m_settingsGroup->property()->removeSubProperty(m_yColumn);
      m_settingsGroup->property()->removeSubProperty(m_errColumn);
    }
  try {
    ws = Mantid::API::AnalysisDataService::Instance().retrieve(workspaceName());
  } catch (...) {
Tom Perkins's avatar
Tom Perkins committed
  // If this is a MuonFitPropertyBrowser, "evaluation type" goes in the Custom
  // Settings group.
  // If not, there is no Custom Settings group and it goes in the regular
  // Settings group.
  auto *settings =
      m_customSettingsGroup ? m_customSettingsGroup : m_settingsGroup;

  settings->property()->removeSubProperty(m_evaluationType);
  m_evaluationType->setEnabled(false);
  // if it is a MatrixWorkspace insert WorkspaceIndex
  auto mws = boost::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(ws);
  if (mws) {
    addWorkspaceIndexToBrowser();
    auto isHistogram = mws->isHistogramData();
    m_evaluationType->setEnabled(isHistogram);
    if (isHistogram) {
      settings->property()->addSubProperty(m_evaluationType);
    }
    return;
  }

  // if it is a TableWorkspace insert the column properties
  auto tws = boost::dynamic_pointer_cast<Mantid::API::ITableWorkspace>(ws);
    setWorkspaceIndex(0);
    // insert properties
    m_settingsGroup->property()->insertSubProperty(m_xColumn, m_workspace);
    m_settingsGroup->property()->insertSubProperty(m_yColumn, m_xColumn);
    m_settingsGroup->property()->insertSubProperty(m_errColumn, m_yColumn);
    if (workspaceName() == m_storedWorkspaceName)
      return;
    QString xName;
    QString yName;
    QString errName;
    auto names = tws->getColumnNames();
    QStringList columns;
    for (size_t i = 0; i < names.size(); ++i) {
      columns << QString::fromStdString(names[i]);
      auto col = tws->getColumn(names[i]);
      if (xName.isEmpty() && col->getPlotType() == 1 /*X*/) {
        xName = QString::fromStdString(names[i]);
      if (yName.isEmpty() && col->getPlotType() == 2 /*Y*/) {
        yName = QString::fromStdString(names[i]);
      if (errName.isEmpty() && col->getPlotType() == 5 /*yErr*/) {
        errName = QString::fromStdString(names[i]);
      }
    }
    m_columnManager->setEnumNames(m_xColumn, columns);
    m_columnManager->setEnumNames(m_yColumn, columns);
    // set the column values
    if (!xName.isEmpty()) {
      m_columnManager->setValue(m_xColumn, columns.indexOf(xName));
    } else {
      foreach (QString name, columns) {
        if (name != yName) {
          m_columnManager->setValue(m_xColumn, columns.indexOf(name));
    if (!yName.isEmpty()) {
      m_columnManager->setValue(m_yColumn, columns.indexOf(yName));
    } else {
      foreach (QString name, columns) {
        if (name != xName) {
          m_columnManager->setValue(m_yColumn, columns.indexOf(name));
          break;
        }
      }
    }
    columns.prepend("");
    m_columnManager->setEnumNames(m_errColumn, columns);
    if (!errName.isEmpty()) {
      m_columnManager->setValue(m_errColumn, columns.indexOf(errName));
void FitPropertyBrowser::addWorkspaceIndexToBrowser() {
  if (m_browser->isItemVisible(m_settingsGroup)) {
    if (!m_settingsGroup->property()->subProperties().contains(
            m_workspaceIndex)) {
      m_settingsGroup->property()->insertSubProperty(m_workspaceIndex,
                                                     m_workspace);
/**=================================================================================================
 * Create a MatrixWorkspace from a TableWorkspace. Name of the TableWorkspace is
 * in m_workspace
 * property, column names to use are in m_xColumn, m_yColumn, and m_errColumn.
 */
Mantid::API::Workspace_sptr
FitPropertyBrowser::createMatrixFromTableWorkspace() const {
  std::string wsName = workspaceName();
    auto ws = Mantid::API::AnalysisDataService::Instance().retrieve(wsName);
    auto tws = boost::dynamic_pointer_cast<Mantid::API::ITableWorkspace>(ws);
    if (!tws)
      return boost::shared_ptr<Mantid::API::Workspace>();
    const size_t rowCount = tws->rowCount();
      QMessageBox::critical(nullptr, "Mantid - Error",
                            "TableWorkspace is empty.");
      return boost::shared_ptr<Mantid::API::Workspace>();
    }

    auto columns = tws->getColumnNames();

    // get the x column
    int ix = m_columnManager->value(m_xColumn);