/** Calculate Chi^2 of the a function with all parameters are fixed */ double RefinePowderInstrumentParameters2::calculateFunctionError(IFunction_sptr function, Workspace2D_sptr dataws, int wsindex) { // 1. Record the fitting information vector<string> parnames = function->getParameterNames(); vector<bool> vecFix(parnames.size(), false); for (size_t i = 0; i < parnames.size(); ++i) { bool fixed = function->isFixed(i); vecFix[i] = fixed; if (!fixed) function->fix(i); } // 2. Fit with zero iteration double chi2; string fitstatus; doFitFunction(function, dataws, wsindex, "Levenberg-MarquardtMD", 0, chi2, fitstatus); // 3. Restore the fit/fix setup for (size_t i = 0; i < parnames.size(); ++i) { if (!vecFix[i]) function->unfix(i); } return chi2; }
/** Add function's parameter names after peak function name */ std::vector<std::string> GeneratePeaks::addFunctionParameterNames(std::vector<std::string> funcnames) { std::vector<std::string> vec_funcparnames; for (size_t i = 0; i < funcnames.size(); ++i) { // Add original name in vec_funcparnames.push_back(funcnames[i]); // Add a full function name and parameter names in IFunction_sptr tempfunc = FunctionFactory::Instance().createFunction(funcnames[i]); std::stringstream parnamess; parnamess << funcnames[i] << " ("; std::vector<std::string> funcpars = tempfunc->getParameterNames(); for (size_t j = 0; j < funcpars.size(); ++j) { parnamess << funcpars[j]; if (j != funcpars.size()-1) parnamess << ", "; } parnamess << ")"; vec_funcparnames.push_back(parnamess.str()); } return vec_funcparnames; }
/** Restore function parameter values saved in a (string,double) map to a function object * and a (string, Parameter) map */ void restoreFunctionParameterValue(map<string, pair<double, double> > parvaluemap, IFunction_sptr function, map<string, Parameter>& parammap) { vector<string> parnames = function->getParameterNames(); for (size_t i = 0; i < parnames.size(); ++i) { string& parname = parnames[i]; map<string, pair<double, double> >::iterator miter; miter = parvaluemap.find(parname); if (miter != parvaluemap.end()) { double parvalue = miter->second.first; double parerror = miter->second.second; // 1. Function function->setParameter(parname, parvalue); // 2. Parameter map map<string, Parameter>::iterator pariter = parammap.find(parname); if (pariter != parammap.end()) { // Find the entry pariter->second.value = parvalue; pariter->second.error = parerror; } } } return; }
/** Fit function * Minimizer: "Levenberg-MarquardtMD"/"Simplex" */ bool RefinePowderInstrumentParameters2::doFitFunction(IFunction_sptr function, Workspace2D_sptr dataws, int wsindex, string minimizer, int numiters, double& chi2, string& fitstatus) { // 0. Debug output stringstream outss; outss << "Fit function: " << m_positionFunc->asString() << endl << "Data To Fit: \n"; for (size_t i = 0; i < dataws->readX(0).size(); ++i) outss << dataws->readX(wsindex)[i] << "\t\t" << dataws->readY(wsindex)[i] << "\t\t" << dataws->readE(wsindex)[i] << "\n"; g_log.information() << outss.str(); // 1. Create and setup fit algorithm API::IAlgorithm_sptr fitalg = createChildAlgorithm("Fit", 0.0, 0.2, true); fitalg->initialize(); fitalg->setProperty("Function", function); fitalg->setProperty("InputWorkspace", dataws); fitalg->setProperty("WorkspaceIndex", wsindex); fitalg->setProperty("Minimizer", minimizer); fitalg->setProperty("CostFunction", "Least squares"); fitalg->setProperty("MaxIterations", numiters); fitalg->setProperty("CalcErrors", true); // 2. Fit bool successfulfit = fitalg->execute(); if (!fitalg->isExecuted() || ! successfulfit) { // Early return due to bad fit g_log.warning("Fitting to instrument geometry function failed. "); chi2 = DBL_MAX; fitstatus = "Minimizer throws exception."; return false; } // 3. Understand solution chi2 = fitalg->getProperty("OutputChi2overDoF"); string tempfitstatus = fitalg->getProperty("OutputStatus"); fitstatus = tempfitstatus; bool goodfit = fitstatus.compare("success") == 0; stringstream dbss; dbss << "Fit Result (GSL): Chi^2 = " << chi2 << "; Fit Status = " << fitstatus << ", Return Bool = " << goodfit << std::endl; vector<string> funcparnames = function->getParameterNames(); for (size_t i = 0; i < funcparnames.size(); ++i) dbss << funcparnames[i] << " = " << setw(20) << function->getParameter(funcparnames[i]) << " +/- " << function->getError(i) << "\n"; g_log.debug() << dbss.str(); return goodfit; }
/** * @brief Returns a string with ties that is passed to Fit * * This method uses the GlobalParameters property, which may contain a comma- * separated list of parameter names that should be the same for all peaks. * * Parameters that do not exist are silently ignored, but a warning is written * to the log so that users have a chance to find typos. * * @param poldiFn :: Function with some parameters. * @return :: String to pass to the Ties-property of Fit. */ std::string PoldiFitPeaks2D::getUserSpecifiedTies(const IFunction_sptr &poldiFn) { std::string tieParameterList = getProperty("GlobalParameters"); if (!tieParameterList.empty()) { std::vector<std::string> tieParameters; boost::split(tieParameters, tieParameterList, boost::is_any_of(",;")); std::vector<std::string> parameters = poldiFn->getParameterNames(); std::vector<std::string> tieComponents; for (auto &tieParameter : tieParameters) { if (!tieParameter.empty()) { std::vector<std::string> matchedParameters; for (auto ¶meter : parameters) { if (boost::algorithm::ends_with(parameter, tieParameter)) { matchedParameters.push_back(parameter); } } switch (matchedParameters.size()) { case 0: g_log.warning("Function does not have a parameter called '" + tieParameter + "', ignoring."); break; case 1: g_log.warning("There is only one peak, no ties necessary."); break; default: { std::string reference = matchedParameters.front(); for (auto par = matchedParameters.begin() + 1; par != matchedParameters.end(); ++par) { tieComponents.push_back(*par + "=" + reference); } break; } } } } if (!tieComponents.empty()) { return boost::algorithm::join(tieComponents, ","); } } return ""; }
/** Store function parameter values to a map */ void storeFunctionParameterValue(IFunction_sptr function, map<string, pair<double, double> >& parvaluemap) { parvaluemap.clear(); vector<string> parnames = function->getParameterNames(); for (size_t i = 0; i < parnames.size(); ++i) { string& parname = parnames[i]; double parvalue = function->getParameter(i); double parerror = function->getError(i); parvaluemap.insert(make_pair(parname, make_pair(parvalue, parerror))); } return; }
/** Set parameter values to function from Parameter map */ void RefinePowderInstrumentParameters2::setFunctionParameterValues(IFunction_sptr function, map<string, Parameter> params) { // 1. Prepare vector<string> funparamnames = function->getParameterNames(); // 2. Set up stringstream msgss; msgss << "Set Instrument Function Parameter : " << endl; std::map<std::string, Parameter>::iterator paramiter; for (size_t i = 0; i < funparamnames.size(); ++i) { string parname = funparamnames[i]; paramiter = params.find(parname); if (paramiter != params.end()) { // Found, set up the parameter Parameter& param = paramiter->second; function->setParameter(parname, param.value); msgss << setw(10) << parname << " = " << param.value << endl; } else { // Not found and thus quit stringstream errss; errss << "Peak profile parameter " << parname << " is not found in input parameters. "; g_log.error(errss.str()); throw runtime_error(errss.str()); } } // ENDFOR parameter name g_log.information(msgss.str()); return; }
void IqtFit::singleFitComplete(bool error) { disconnect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), this, SLOT(singleFitComplete(bool))); if (error) { QString msg = "There was an error executing the fitting algorithm. Please see the " "Results Log pane for more details."; showMessageBox(msg); return; } IFunction_sptr outputFunc = m_singleFitAlg->getProperty("Function"); // Get params. QMap<QString, double> parameters; std::vector<std::string> parNames = outputFunc->getParameterNames(); std::vector<double> parVals; for (size_t i = 0; i < parNames.size(); ++i) parVals.push_back(outputFunc->getParameter(parNames[i])); for (size_t i = 0; i < parNames.size(); ++i) parameters[QString(parNames[i].c_str())] = parVals[i]; m_ffRangeManager->setValue(m_properties["BackgroundA0"], parameters["f0.A0"]); const int fitType = m_uiForm.cbFitType->currentIndex(); if (fitType != 2) { // Exp 1 m_dblManager->setValue(m_properties["Exponential1.Intensity"], parameters["f1.Intensity"]); m_dblManager->setValue(m_properties["Exponential1.Tau"], parameters["f1.Tau"]); if (fitType == 1) { // Exp 2 m_dblManager->setValue(m_properties["Exponential2.Intensity"], parameters["f2.Intensity"]); m_dblManager->setValue(m_properties["Exponential2.Tau"], parameters["f2.Tau"]); } } if (fitType > 1) { // Str QString fval; if (fitType == 2) { fval = "f1."; } else { fval = "f2."; } m_dblManager->setValue(m_properties["StretchedExp.Intensity"], parameters[fval + "Intensity"]); m_dblManager->setValue(m_properties["StretchedExp.Tau"], parameters[fval + "Tau"]); m_dblManager->setValue(m_properties["StretchedExp.Beta"], parameters[fval + "Beta"]); } // Can start upddating the guess curve again connect(m_dblManager, SIGNAL(propertyChanged(QtProperty *)), this, SLOT(plotGuess(QtProperty *))); // Plot the guess first so that it is under the fit plotGuess(NULL); // Now show the fitted curve of the mini plot m_uiForm.ppPlot->addSpectrum("Fit", m_singleFitOutputName + "_Workspace", 1, Qt::red); m_pythonExportWsName = ""; }