Skip to content
Snippets Groups Projects
ConvFit.cpp 48.9 KiB
Newer Older
  m_singleFitAlg->initialize();
  m_singleFitAlg->setPropertyValue("Function", function->asString());
  m_singleFitAlg->setPropertyValue("InputWorkspace",
                                   m_cfInputWSName.toStdString());
  m_singleFitAlg->setProperty<int>("WorkspaceIndex",
                                   m_uiForm.spPlotSpectrum->text().toInt());
  m_singleFitAlg->setProperty<double>(
      "StartX", m_dblManager->value(m_properties["StartX"]));
  m_singleFitAlg->setProperty<double>(
      "EndX", m_dblManager->value(m_properties["EndX"]));
  m_singleFitAlg->setProperty("Output", m_singleFitOutputName.toStdString());
  m_singleFitAlg->setProperty("CreateOutput", true);
  m_singleFitAlg->setProperty("OutputCompositeMembers", true);
  m_singleFitAlg->setProperty("ConvolveMembers", true);
  m_singleFitAlg->setProperty("MaxIterations", maxIterations);
  m_singleFitAlg->setProperty(
      "Minimizer", minimizerString(m_singleFitOutputName).toStdString());

  m_batchAlgoRunner->addAlgorithm(m_singleFitAlg);
  connect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), this,
          SLOT(singleFitComplete(bool)));
  m_batchAlgoRunner->executeBatchAsync();
}
/**
 * Handle completion of the fit algorithm for single fit.
 *
 * @param error If the fit algorithm failed
 */
void ConvFit::singleFitComplete(bool error) {
  disconnect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), this,
             SLOT(singleFitComplete(bool)));

  if (error) {
    showMessageBox("Fit algorithm failed.");
    return;
  }
  // Plot the line on the mini plot
  m_uiForm.ppPlot->removeSpectrum("Guess");
  m_uiForm.ppPlot->addSpectrum("Fit", m_singleFitOutputName + "_Workspace", 1,
                               Qt::red);
  IFunction_sptr outputFunc = m_singleFitAlg->getProperty("Function");
  QString functionName = m_uiForm.cbFitType->currentText();

  // Get params.
  QMap<QString, double> parameters;
  std::vector<std::string> parNames = outputFunc->getParameterNames();
  std::vector<double> parVals;
  QStringList params = getFunctionParameters(functionName);

  for (size_t i = 0; i < parNames.size(); ++i)
    parVals.push_back(outputFunc->getParameter(parNames[i]));
  for (size_t i = 0; i < parNames.size(); ++i)
    parameters[QString(parNames[i].c_str())] = parVals[i];
  // Populate Tree widget with values
  // Background should always be f0
  m_dblManager->setValue(m_properties["BGA0"], parameters["f0.A0"]);
  m_dblManager->setValue(m_properties["BGA1"], parameters["f0.A1"]);
  int fitTypeIndex = m_uiForm.cbFitType->currentIndex();
  int funcIndex = 0;
  int subIndex = 0;
  // check if we're using a temperature correction
  if (m_uiForm.ckTempCorrection->isChecked() &&
      !m_uiForm.leTempCorrection->text().isEmpty()) {
    subIndex++;
  }
  bool usingDeltaFunc = m_blnManager->value(m_properties["UseDeltaFunc"]);
  // If using a delta function with any fit type or using two Lorentzians
  bool usingCompositeFunc =
      ((usingDeltaFunc && fitTypeIndex > 0) || fitTypeIndex == 2);
  QString prefBase = "f1.f1.";
  if (usingDeltaFunc) {
    QString key = prefBase;
    if (usingCompositeFunc) {
      key += "f0.";
    m_dblManager->setValue(m_properties["DeltaHeight"], parameters[key]);
    funcIndex++;
  QString pref = prefBase;
  if (usingCompositeFunc) {
    pref += "f" + QString::number(funcIndex) + ".f" +
            QString::number(subIndex) + ".";
  } else {
    pref += "f" + QString::number(subIndex) + ".";
  }
  if (fitTypeIndex == 1 || fitTypeIndex == 2) {
    functionName = "Lorentzian 1";
  if (fitTypeIndex == 2) {
    for (auto it = params.begin(); it != params.end() - 3; ++it) {
      QString functionParam = functionName + "." + *it;
      QString paramValue = pref + *it;
      m_dblManager->setValue(m_properties[functionParam],
                             parameters[paramValue]);
    }
    pref += "f" + QString::number(funcIndex) + ".f" +
            QString::number(subIndex) + ".";

    functionName = "Lorentzian 2";
    for (auto it = params.begin() + 3; it != params.end(); ++it) {
      QString functionParam = functionName + "." + *it;
      QString paramValue = pref + *it;
      m_dblManager->setValue(m_properties[functionParam],
                             parameters[paramValue]);
    }

  } else {
    for (auto it = params.begin(); it != params.end(); ++it) {
      QString functionParam = functionName + "." + *it;
      QString paramValue = pref + *it;
      m_dblManager->setValue(m_properties[functionParam],
                             parameters[paramValue]);
    }
  m_pythonExportWsName = "";
}
/**
 * Handles the user entering a new minimum spectrum index.
 *
 * Prevents the user entering an overlapping spectra range.
 *
 * @param value Minimum spectrum index
 */
void ConvFit::specMinChanged(int value) {
  m_uiForm.spSpectraMax->setMinimum(value);
}
/**
 * Handles the user entering a new maximum spectrum index.
 *
 * Prevents the user entering an overlapping spectra range.
 *
 * @param value Maximum spectrum index
 */
void ConvFit::specMaxChanged(int value) {
  m_uiForm.spSpectraMin->setMaximum(value);
}
void ConvFit::minChanged(double val) {
  m_dblManager->setValue(m_properties["StartX"], val);
}
void ConvFit::maxChanged(double val) {
  m_dblManager->setValue(m_properties["EndX"], val);
}
void ConvFit::hwhmChanged(double val) {
  const double peakCentre =
      m_dblManager->value(m_properties["Lorentzian 1.PeakCentre"]);
  // Always want FWHM to display as positive.
  const double hwhm = std::fabs(val - peakCentre);
  // Update the property
  auto hwhmRangeSelector = m_uiForm.ppPlot->getRangeSelector("ConvFitHWHM");
  hwhmRangeSelector->blockSignals(true);
  m_dblManager->setValue(m_properties["Lorentzian 1.FWHM"], hwhm * 2);
  hwhmRangeSelector->blockSignals(false);
}
void ConvFit::backgLevel(double val) {
  m_dblManager->setValue(m_properties["BGA0"], val);
}
void ConvFit::updateRS(QtProperty *prop, double val) {
  auto fitRangeSelector = m_uiForm.ppPlot->getRangeSelector("ConvFitRange");
  auto backRangeSelector =
      m_uiForm.ppPlot->getRangeSelector("ConvFitBackRange");

  if (prop == m_properties["StartX"]) {
    fitRangeSelector->setMinimum(val);
  } else if (prop == m_properties["EndX"]) {
    fitRangeSelector->setMaximum(val);
  } else if (prop == m_properties["BGA0"]) {
    backRangeSelector->setMinimum(val);
  } else if (prop == m_properties["Lorentzian 1.FWHM"]) {
    hwhmUpdateRS(val);
  } else if (prop == m_properties["Lorentzian 1.PeakCentre"]) {
    hwhmUpdateRS(m_dblManager->value(m_properties["Lorentzian 1.FWHM"]));
  }
}
void ConvFit::hwhmUpdateRS(double val) {
  const double peakCentre =
      m_dblManager->value(m_properties["Lorentzian 1.PeakCentre"]);
  auto hwhmRangeSelector = m_uiForm.ppPlot->getRangeSelector("ConvFitHWHM");
  hwhmRangeSelector->setMinimum(peakCentre - val / 2);
  hwhmRangeSelector->setMaximum(peakCentre + val / 2);
}
void ConvFit::checkBoxUpdate(QtProperty *prop, bool checked) {
  UNUSED_ARG(checked);
  if (prop == m_properties["UseDeltaFunc"])
    updatePlotOptions();
  else if (prop == m_properties["UseFABADA"]) {
    if (checked) {
      // FABADA needs a much higher iteration limit
      m_dblManager->setValue(m_properties["MaxIterations"], 20000);

      m_properties["FABADA"]->addSubProperty(m_properties["OutputFABADAChain"]);
      m_properties["FABADA"]->addSubProperty(m_properties["FABADAChainLength"]);
      m_properties["FABADA"]->addSubProperty(
          m_properties["FABADAConvergenceCriteria"]);
      m_properties["FABADA"]->addSubProperty(
          m_properties["FABADAJumpAcceptanceRate"]);
    } else {
      m_dblManager->setValue(m_properties["MaxIterations"], 500);

      m_properties["FABADA"]->removeSubProperty(
          m_properties["OutputFABADAChain"]);
      m_properties["FABADA"]->removeSubProperty(
          m_properties["FABADAChainLength"]);
      m_properties["FABADA"]->removeSubProperty(
          m_properties["FABADAConvergenceCriteria"]);
      m_properties["FABADA"]->removeSubProperty(
          m_properties["FABADAJumpAcceptanceRate"]);
void ConvFit::fitContextMenu(const QPoint &) {
  QtBrowserItem *item(NULL);
  item = m_cfTree->currentItem();
  // is it a fit property ?
  QtProperty *prop = item->property();
  if (prop == m_properties["StartX"] || prop == m_properties["EndX"])
    return;
  // is it already fixed?
  bool fixed = prop->propertyManager() != m_dblManager;
  if (fixed && prop->propertyManager() != m_stringManager)
    return;
  // Create the menu
  QMenu *menu = new QMenu("ConvFit", m_cfTree);
  QAction *action;
  if (!fixed) {
    action = new QAction("Fix", m_parentWidget);
    connect(action, SIGNAL(triggered()), this, SLOT(fixItem()));
  } else {
    action = new QAction("Remove Fix", m_parentWidget);
    connect(action, SIGNAL(triggered()), this, SLOT(unFixItem()));
  menu->addAction(action);
  // Show the menu
  menu->popup(QCursor::pos());
}
void ConvFit::fixItem() {
  QtBrowserItem *item = m_cfTree->currentItem();
  // Determine what the property is.
  QtProperty *prop = item->property();
  QtProperty *fixedProp = m_stringManager->addProperty(prop->propertyName());
  QtProperty *fprlbl = m_stringManager->addProperty("Fixed");
  fixedProp->addSubProperty(fprlbl);
  m_stringManager->setValue(fixedProp, prop->valueText());
  item->parent()->property()->addSubProperty(fixedProp);
  m_fixedProps[fixedProp] = prop;
  item->parent()->property()->removeSubProperty(prop);
}
void ConvFit::unFixItem() {
  QtBrowserItem *item = m_cfTree->currentItem();
  QtProperty *prop = item->property();
  if (prop->subProperties().empty()) {
    item = item->parent();
    prop = item->property();
  }
  item->parent()->property()->addSubProperty(m_fixedProps[prop]);
  item->parent()->property()->removeSubProperty(prop);
  m_fixedProps.remove(prop);
  QtProperty *proplbl = prop->subProperties()[0];
  delete proplbl;
  delete prop;
}
void ConvFit::showTieCheckbox(QString fitType) {
  m_uiForm.ckTieCentres->setVisible(fitType == "Two Lorentzians");
}
/**
 * Gets a list of parameters for a given fit function.
 * @return List fo parameters
 */
QStringList ConvFit::getFunctionParameters(QString functionName) {
  if (functionName.compare("Two Lorentzians") == 0) {
    functionName = "Lorentzian";
    IFunction_sptr func =
        FunctionFactory::Instance().createFunction(functionName.toStdString());

    for (size_t i = 0; i < func->nParams(); i++) {
      parameters << QString::fromStdString(func->parameterName(i));
  if (functionName.compare("One Lorentzian") == 0) {
    functionName = "Lorentzian";
  if (functionName.compare("Zero Lorentzians") == 0) {
    parameters.append("Zero");
  } else {
    IFunction_sptr func =
        FunctionFactory::Instance().createFunction(functionName.toStdString());
    for (size_t i = 0; i < func->nParams(); i++) {
      parameters << QString::fromStdString(func->parameterName(i));
    }

  return parameters;
}

/**
 * Handles a new fit function being selected.
 * @param functionName Name of new fit function
 */
void ConvFit::fitFunctionSelected(const QString &functionName) {
  // remove previous parameters from tree
  m_cfTree->removeProperty(m_properties["FitFunction1"]);
  m_cfTree->removeProperty(m_properties["FitFunction2"]);
  m_uiForm.ckPlotGuess->setChecked(false);
  m_uiForm.ckTieCentres->setChecked(false);
  // Add new parameter elements
  int fitFunctionIndex = m_uiForm.cbFitType->currentIndex();
  QStringList parameters = getFunctionParameters(functionName);
  updatePlotOptions();
  if (fitFunctionIndex == 2) {
    m_properties["FitFunction1"] = m_grpManager->addProperty("Lorentzian 1");
    m_cfTree->addProperty(m_properties["FitFunction1"]);
    m_properties["FitFunction2"] = m_grpManager->addProperty("Lorentzian 2");
    m_cfTree->addProperty(m_properties["FitFunction2"]);
  } else {
    m_properties["FitFunction1"] = m_grpManager->addProperty(functionName);
    m_cfTree->addProperty(m_properties["FitFunction1"]);
  }
  // No fit function parameters required for Zero
  if (parameters[0].compare("Zero") != 0) {
    if (fitFunctionIndex == 2) {
      propName = "Lorentzian 1";
      for (auto it = parameters.begin(); it != parameters.end(); ++it) {
        if (count == 3) {
          propName = "Lorentzian 2";
        }
        QString name = propName + "." + *it;
        m_properties[name] = m_dblManager->addProperty(*it);

        if (QString(*it).compare("FWHM") == 0) {
          m_dblManager->setValue(m_properties[name], 0.0175);
        } else {
          m_dblManager->setValue(m_properties[name], 0.0);
        }
        if (QString(*it).compare("Amplitude") == 0 ||
            QString(*it).compare("Intensity") == 0) {
          m_dblManager->setValue(m_properties[name], 1.0);
        }
        m_dblManager->setDecimals(m_properties[name], NUM_DECIMALS);
        if (count < 3) {
          m_properties["FitFunction1"]->addSubProperty(m_properties[name]);
        } else {
          m_properties["FitFunction2"]->addSubProperty(m_properties[name]);
        }
        count++;
      }
    } else {
      if (fitFunctionIndex == 1) {
        propName = "Lorentzian 1";
      } else {
        propName = functionName;
      }
      for (auto it = parameters.begin(); it != parameters.end(); ++it) {
        QString name = propName + "." + *it;
        m_properties[name] = m_dblManager->addProperty(*it);

        if (QString(*it).compare("FWHM") == 0) {
          m_dblManager->setValue(m_properties[name], 0.0175);
        } else {
          m_dblManager->setValue(m_properties[name], 0.0);
        }
        if (QString(*it).compare("Amplitude") == 0 ||
            QString(*it).compare("Intensity") == 0) {
          m_dblManager->setValue(m_properties[name], 1.0);
        }
        m_dblManager->setDecimals(m_properties[name], NUM_DECIMALS);
        m_properties["FitFunction1"]->addSubProperty(m_properties[name]);
/**
 * Populates the plot combobox
 */
void ConvFit::updatePlotOptions() {
  m_uiForm.cbPlotType->clear();

  const bool deltaFunction = m_blnManager->value(m_properties["UseDeltaFunc"]);
  const int fitFunctionType = m_uiForm.cbFitType->currentIndex();
  QStringList plotOptions;
  plotOptions << "None";

  if (deltaFunction && fitFunctionType < 3) {
    plotOptions << "Height";
  }
  QStringList params = QStringList();
  if (fitFunctionType != 2) {
    params = getFunctionParameters(m_uiForm.cbFitType->currentText());
  } else {
    params = getFunctionParameters(QString("One Lorentzian"));
  }
  if (fitFunctionType != 0) {
    plotOptions.append(params);
  }

  if (fitFunctionType != 0 || deltaFunction) {
    plotOptions << "All";
  }
  m_uiForm.cbPlotType->addItems(plotOptions);
}

} // namespace IDA
} // namespace CustomInterfaces
} // namespace MantidQt