TEST(FunctionFactoryTest, CreateCompositeFunctionTest) { std::string ini = "CompositeFunction(" "FunctionFactoryTestFunction(A=10,B=20)," "FunctionFactoryTestFunction(A=30,B=40)" ")"; IFunction_sptr fun = FunctionFactory::instance().createFitFunction(ini); EXPECT_TRUE( fun.get() != nullptr ); CompositeFunction_sptr cf = boost::dynamic_pointer_cast<CompositeFunction>(fun); EXPECT_TRUE( cf.get() != nullptr ); EXPECT_EQ( cf->nFunctions(), 2 ); auto f1 = cf->getFunction(0); auto f2 = cf->getFunction(1); EXPECT_EQ(f1->getParameter("A"),10); EXPECT_EQ(f1->getParameter("B"),20); EXPECT_EQ(f2->getParameter("A"),30); EXPECT_EQ(f2->getParameter("B"),40); EXPECT_EQ(cf->getParameter("f0.A"),10); EXPECT_EQ(cf->getParameter("f0.B"),20); EXPECT_EQ(cf->getParameter("f1.A"),30); EXPECT_EQ(cf->getParameter("f1.B"),40); std::cerr << '\n' << fun->asString(true) << '\n' << std::endl; IFunction_sptr fun1 = FunctionFactory::instance().createFitFunction(ini); EXPECT_TRUE( fun1.get() != nullptr ); cf = boost::dynamic_pointer_cast<CompositeFunction>(fun1); EXPECT_TRUE( cf.get() != nullptr ); EXPECT_EQ( cf->nFunctions(), 2 ); EXPECT_EQ(cf->getParameter("f0.A"),10); EXPECT_EQ(cf->getParameter("f0.B"),20); EXPECT_EQ(cf->getParameter("f1.A"),30); EXPECT_EQ(cf->getParameter("f1.B"),40); }
/** * Initialize diagnosis table. */ void MuonSequentialFitDialog::initDiagnosisTable() { QStringList headerLabels; // Add two static columns headerLabels << "Run" << "Fit quality"; // Add remaining columns - one for every fit function parameter IFunction_sptr fitFunc = m_fitPropBrowser->getFittingFunction(); for(size_t i = 0; i < fitFunc->nParams(); i++) { QString paramName = QString::fromStdString( fitFunc->parameterName(i) ); headerLabels << paramName; headerLabels << paramName + "_Err"; } m_ui.diagnosisTable->setColumnCount( headerLabels.size() ); m_ui.diagnosisTable->setHorizontalHeaderLabels(headerLabels); // Make the table fill all the available space and columns be resized to fit contents m_ui.diagnosisTable->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents); // Make rows alternate bg colors for better user experience m_ui.diagnosisTable->setAlternatingRowColors(true); }
IFunction_sptr IqtFit::createUserFunction(const QString &name, bool tie) { IFunction_sptr result = FunctionFactory::Instance().createFunction("UserFunction"); std::string formula; if (name.startsWith("Exp")) { formula = "Intensity*exp(-(x/Tau))"; } else { formula = "Intensity*exp(-(x/Tau)^Beta)"; } IFunction::Attribute att(formula); result->setAttribute("Formula", att); QList<QtProperty *> props = m_properties[name]->subProperties(); for (int i = 0; i < props.size(); i++) { std::string name = props[i]->propertyName().toStdString(); result->setParameter(name, m_dblManager->value(props[i])); // add tie if parameter is fixed if (tie || !props[i]->subProperties().isEmpty()) { std::string value = props[i]->valueText().toStdString(); result->tie(name, value); } } result->applyTies(); return result; }
/** 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; }
/** 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 a new entry to the diagnosis table. * @param runTitle :: Title of the run fitted * @param fitQuality :: Number representing a goodness of the fit * @param fittedFunction :: Function containing fitted parameters */ void MuonSequentialFitDialog::addDiagnosisEntry(const std::string& runTitle, double fitQuality, IFunction_sptr fittedFunction) { int newRow = m_ui.diagnosisTable->rowCount(); m_ui.diagnosisTable->insertRow(newRow); QString runTitleDisplay = QString::fromStdString(runTitle); m_ui.diagnosisTable->setItem( newRow, 0, createTableWidgetItem(runTitleDisplay) ); QString fitQualityDisplay = QString::number(fitQuality); m_ui.diagnosisTable->setItem( newRow, 1, createTableWidgetItem(fitQualityDisplay) ); for(int i = 2; i < m_ui.diagnosisTable->columnCount(); i += 2) { std::string paramName = m_ui.diagnosisTable->horizontalHeaderItem(i)->text().toStdString(); size_t paramIndex = fittedFunction->parameterIndex(paramName); QString value = QString::number( fittedFunction->getParameter(paramIndex) ); QString error = QString::number( fittedFunction->getError(paramIndex) ); m_ui.diagnosisTable->setItem(newRow, i, createTableWidgetItem(value) ); m_ui.diagnosisTable->setItem(newRow, i + 1, createTableWidgetItem(error) ); } m_ui.diagnosisTable->scrollToBottom(); }
/** 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; }
/* Propagate the attribute to its member functions. * NOTE: we pass this->getAttribute(name) by reference, thus the same * object is shared by the composite function and its members. */ void DiffSphere::trickleDownAttribute(const std::string &name) { for (size_t iFun = 0; iFun < nFunctions(); iFun++) { IFunction_sptr fun = getFunction(iFun); if (fun->hasAttribute(name)) { fun->setAttribute(name, this->getAttribute(name)); } } }
TEST(FunctionFactoryTest, CreateFitFunctionTest) { IFunction_sptr fun = FunctionFactory::instance().createFitFunction("FunctionFactoryTestFunction(A=10,B=20)"); EXPECT_TRUE( fun.get() != nullptr ); EXPECT_EQ(fun->getParameter("A"),10); EXPECT_EQ(fun->getParameter("B"),20); //std::cerr << fun->asString() << std::endl; }
/** * Returns the shrared pointer to the function conataining a parameter * @param ref :: The reference * @return A function containing parameter pointed to by ref */ IFunction_sptr CompositeFunction::getContainingFunction(const ParameterReference &ref) const { for (size_t iFun = 0; iFun < nFunctions(); iFun++) { IFunction_sptr fun = getFunction(iFun); if (fun->getParameterIndex(ref) < fun->nParams()) { return fun; } } return IFunction_sptr(); }
/** * Gets a list of parameters for a given fit function. * * @return List fo parameters */ QStringList JumpFit::getFunctionParameters(const QString &functionName) { QStringList parameters; 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; }
/** 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; }
/** Set parameter fitting setup (boundary, fix or unfix) to function from Parameter map */ void RefinePowderInstrumentParameters2::setFunctionParameterFitSetups(IFunction_sptr function, map<string, Parameter> params) { // 1. Prepare vector<string> funparamnames = m_positionFunc->getParameterNames(); // 2. Set up 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; if (param.fit) { // If fit. Unfix it and set up constraint function->unfix(i); double lowerbound = param.minvalue; double upperbound = param.maxvalue; if (lowerbound >= -DBL_MAX*0.1 || upperbound <= DBL_MAX*0.1) { // If there is a boundary BoundaryConstraint *bc = new BoundaryConstraint(function.get(), parname, lowerbound, upperbound, false); function->addConstraint(bc); } } else { // If fix. function->fix(i); } } 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.notice() << "Fit function:\n" << function->asString() << "\n"; return; }
/** Add a function * @param f :: A pointer to the added function * @return The function index */ size_t CompositeFunction::addFunction(IFunction_sptr f) { m_IFunction.insert(m_IFunction.end(), f->nParams(), m_functions.size()); m_functions.push_back(f); //?f->init(); if (m_paramOffsets.empty()) { m_paramOffsets.push_back(0); m_nParams = f->nParams(); } else { m_paramOffsets.push_back(m_nParams); m_nParams += f->nParams(); } return m_functions.size() - 1; }
/** * Gets the new attribute values to be updated in the function and in the fit * property browser. * @param function The function containing the attributes * @param attributeNames The names of the attributes to update */ std::unordered_map<std::string, IFunction::Attribute> IndirectFitAnalysisTab::getAttributes( IFunction_sptr const &function, std::vector<std::string> const &attributeNames) { std::unordered_map<std::string, IFunction::Attribute> attributes; for (auto const &name : attributeNames) if (function->hasAttribute(name)) attributes[name] = name == "WorkspaceIndex" ? IFunction::Attribute(m_fitPropertyBrowser->workspaceIndex()) : function->getAttribute(name); return attributes; }
/// Returns a TableWorkspace with refined cell parameters and error. ITableWorkspace_sptr PoldiFitPeaks2D::getRefinedCellParameters( const IFunction_sptr &fitFunction) const { Poldi2DFunction_sptr poldi2DFunction = boost::dynamic_pointer_cast<Poldi2DFunction>(fitFunction); if (!poldi2DFunction || poldi2DFunction->nFunctions() < 1) { throw std::invalid_argument( "Cannot process function that is not a Poldi2DFunction."); } // Create a new table for lattice parameters ITableWorkspace_sptr latticeParameterTable = WorkspaceFactory::Instance().createTable(); latticeParameterTable->addColumn("str", "Parameter"); latticeParameterTable->addColumn("double", "Value"); latticeParameterTable->addColumn("double", "Error"); // The first function should be PoldiSpectrumPawleyFunction boost::shared_ptr<PoldiSpectrumPawleyFunction> poldiPawleyFunction = boost::dynamic_pointer_cast<PoldiSpectrumPawleyFunction>( poldi2DFunction->getFunction(0)); if (!poldiPawleyFunction) { throw std::invalid_argument("First function in Poldi2DFunction is not " "PoldiSpectrumPawleyFunction."); } // Get the actual PawleyFunction to extract parameters. IPawleyFunction_sptr pawleyFunction = boost::dynamic_pointer_cast<IPawleyFunction>( poldiPawleyFunction->getDecoratedFunction()); if (pawleyFunction) { CompositeFunction_sptr pawleyParts = boost::dynamic_pointer_cast<CompositeFunction>( pawleyFunction->getDecoratedFunction()); // The first function in PawleyFunction contains the parameters IFunction_sptr pawleyParameters = pawleyParts->getFunction(0); for (size_t i = 0; i < pawleyParameters->nParams(); ++i) { TableRow newRow = latticeParameterTable->appendRow(); newRow << pawleyParameters->parameterName(i) << pawleyParameters->getParameter(i) << pawleyParameters->getError(i); } } return latticeParameterTable; }
/** * Returns the index of parameter if the ref points to one of the member * function * @param ref :: A reference to a parameter * @return Parameter index or number of nParams() if parameter not found */ size_t CompositeFunction::getParameterIndex(const ParameterReference &ref) const { if (ref.getLocalFunction() == this && ref.getLocalIndex() < nParams()) { return ref.getLocalIndex(); } for (size_t iFun = 0; iFun < nFunctions(); iFun++) { IFunction_sptr fun = getFunction(iFun); size_t iLocalIndex = fun->getParameterIndex(ref); if (iLocalIndex < fun->nParams()) { return m_paramOffsets[iFun] + iLocalIndex; } } return nParams(); }
TEST(FunctionFactoryTest, CreateFitFunction_with_brackets_Test) { IFunction_sptr fun = FunctionFactory::instance().createFitFunction("FunctionFactoryTestFunction()"); EXPECT_TRUE( fun.get() != nullptr ); //Function1DTestFunction fun; FunctionDomain1DVector domain(0.0,1.0,10); FunctionValues values(domain); fun->function(domain,values); for(size_t i = 0; i < domain.size(); ++i) { double x = domain[i]; EXPECT_EQ( 1.0 * x - 3.0, values.getCalculated(i)); } }
/** * Add a new workspace to the fit. The workspace is in the property named * workspacePropertyName. * @param workspacePropertyName :: A workspace property name (eg InputWorkspace * or InputWorkspace_2). The property must already exist in the algorithm. * @param addProperties :: allow for declaration of properties that specify the * dataset within the workspace to fit to. */ void IFittingAlgorithm::addWorkspace(const std::string &workspacePropertyName, bool addProperties) { // get the workspace API::Workspace_const_sptr ws = getProperty(workspacePropertyName); // m_function->setWorkspace(ws); const size_t n = std::string("InputWorkspace").size(); const std::string suffix = (workspacePropertyName.size() > n) ? workspacePropertyName.substr(n) : ""; const size_t index = suffix.empty() ? 0 : boost::lexical_cast<size_t>(suffix.substr(1)); IFunction_sptr fun = getProperty("Function"); setDomainType(); IDomainCreator *creator = createDomainCreator( fun.get(), ws.get(), workspacePropertyName, this, m_domainType); if (!m_domainCreator) { if (m_workspacePropertyNames.empty()) { // this defines the function and fills in m_workspacePropertyNames with // names of the sort InputWorkspace_# setFunction(); } auto multiFun = boost::dynamic_pointer_cast<API::MultiDomainFunction>(fun); if (multiFun) { auto multiCreator = new MultiDomainCreator(this, m_workspacePropertyNames); multiCreator->setCreator(index, creator); m_domainCreator.reset(multiCreator); creator->declareDatasetProperties(suffix, addProperties); } else { m_domainCreator.reset(creator); creator->declareDatasetProperties(suffix, addProperties); } } else { boost::shared_ptr<MultiDomainCreator> multiCreator = boost::dynamic_pointer_cast<MultiDomainCreator>(m_domainCreator); if (!multiCreator) { auto &reference = *m_domainCreator.get(); throw std::runtime_error( std::string("MultiDomainCreator expected, found ") + typeid(reference).name()); } if (!multiCreator->hasCreator(index)) { creator->declareDatasetProperties(suffix, addProperties); } multiCreator->setCreator(index, creator); } }
/** 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 any WorkspaceIndex attributes in the fitting function. If the function is composite * try all its members. * @param fun :: The fitting function * @param wsIndex :: Value for WorkspaceIndex attributes to set. */ void PlotPeakByLogValue::setWorkspaceIndexAttribute(IFunction_sptr fun, int wsIndex) const { const std::string attName = "WorkspaceIndex"; if ( fun->hasAttribute(attName) ) { fun->setAttributeValue(attName,wsIndex); } API::CompositeFunction_sptr cf = boost::dynamic_pointer_cast<API::CompositeFunction>( fun ); if ( cf ) { for(size_t i = 0; i < cf->nFunctions(); ++i) { setWorkspaceIndexAttribute( cf->getFunction(i), wsIndex ); } } }
/// Execute void EstimatePeakErrors::exec() { IFunction_sptr function = getProperty("Function"); ITableWorkspace_sptr results = WorkspaceFactory::Instance().createTable("TableWorkspace"); results->addColumn("str", "Parameter"); results->addColumn("double", "Value"); results->addColumn("double", "Error"); auto matrix = function->getCovarianceMatrix(); if (!matrix) { g_log.warning() << "Function doesn't have covariance matrix.\n"; setProperty("OutputWorkspace", results); return; } IPeakFunction *peak = dynamic_cast<IPeakFunction *>(function.get()); if (peak) { GSLMatrix covariance(*matrix); calculatePeakValues(*peak, *results, covariance, ""); } else { CompositeFunction *cf = dynamic_cast<CompositeFunction *>(function.get()); if (cf) { size_t ip = 0; for (size_t i = 0; i < cf->nFunctions(); ++i) { IFunction *fun = cf->getFunction(i).get(); size_t np = fun->nParams(); peak = dynamic_cast<IPeakFunction *>(fun); if (peak) { std::string prefix = "f" + std::to_string(i) + "."; GSLMatrix covariance(*matrix, ip, ip, np, np); calculatePeakValues(*peak, *results, covariance, prefix); } ip += np; } } else { g_log.warning() << "Function has no peaks.\n"; } } setProperty("OutputWorkspace", results); }
/** Remove a function * @param i :: The index of the function to remove */ void CompositeFunction::removeFunction(size_t i) { if (i >= nFunctions()) { throw std::out_of_range("Function index (" + std::to_string(i) + ") out of range (" + std::to_string(nFunctions()) + ")."); } IFunction_sptr fun = getFunction(i); // Reduction in parameters size_t dnp = fun->nParams(); for (size_t j = 0; j < nParams();) { ParameterTie *tie = getTie(j); if (tie && tie->findParametersOf(fun.get())) { removeTie(j); } else { j++; } } // Shift down the function indeces for parameters for (auto it = m_IFunction.begin(); it != m_IFunction.end();) { if (*it == i) { it = m_IFunction.erase(it); } else { if (*it > i) { *it -= 1; } ++it; } } m_nParams -= dnp; // Shift the parameter offsets down by the total number of i-th function's // params for (size_t j = i + 1; j < nFunctions(); j++) { m_paramOffsets[j] -= dnp; } m_paramOffsets.erase(m_paramOffsets.begin() + i); m_functions.erase(m_functions.begin() + i); }
/** Replace a function with a new one. The old function is deleted. * @param i :: The index of the function to replace * @param f :: A pointer to the new function */ void CompositeFunction::replaceFunction(size_t i, IFunction_sptr f) { if (i >= nFunctions()) { throw std::out_of_range("Function index (" + std::to_string(i) + ") out of range (" + std::to_string(nFunctions()) + ")."); } IFunction_sptr fun = getFunction(i); size_t np_old = fun->nParams(); size_t np_new = f->nParams(); // Modify function indeces: The new function may have different number of // parameters { auto itFun = std::find(m_IFunction.begin(), m_IFunction.end(), i); if (itFun != m_IFunction.end()) // functions must have at least 1 parameter { if (np_old > np_new) { m_IFunction.erase(itFun, itFun + np_old - np_new); } else if (np_old < np_new) { m_IFunction.insert(itFun, np_new - np_old, i); } } else if (np_new > 0) // it could happen if the old function is an empty // CompositeFunction { itFun = std::find_if(m_IFunction.begin(), m_IFunction.end(), std::bind2nd(std::greater<size_t>(), i)); m_IFunction.insert(itFun, np_new, i); } } size_t dnp = np_new - np_old; m_nParams += dnp; // Shift the parameter offsets down by the total number of i-th function's // params for (size_t j = i + 1; j < nFunctions(); j++) { m_paramOffsets[j] += dnp; } m_functions[i] = f; }
/** * @param fun :: The function * @param expr :: The tie expression: parName = TieString */ void FunctionFactoryImpl::addTie(IFunction_sptr fun, const Expression &expr) const { if (expr.size() > 1) { // if size > 2 it is interpreted as setting a tie (last // expr.term) to multiple parameters, e.g // f1.alpha = f2.alpha = f3.alpha = f0.beta^2/2 const std::string value = expr[expr.size() - 1].str(); for (size_t i = expr.size() - 1; i != 0;) { --i; fun->tie(expr[i].name(), value); } } }
/** * Adds background functions for the background if applicable * * If specified by the user via the corresponding algorithm parameters, * this function adds a constant and a linear background term to the * supplied Poldi2DFunction. * * @param poldi2DFunction :: Poldi2DFunction to which the background is added. */ void PoldiFitPeaks2D::addBackgroundTerms( Poldi2DFunction_sptr poldi2DFunction) const { bool addConstantBackground = getProperty("FitConstantBackground"); if (addConstantBackground) { IFunction_sptr constantBackground = FunctionFactory::Instance().createFunction( "PoldiSpectrumConstantBackground"); constantBackground->setParameter( 0, getProperty("ConstantBackgroundParameter")); poldi2DFunction->addFunction(constantBackground); } bool addLinearBackground = getProperty("FitLinearBackground"); if (addLinearBackground) { IFunction_sptr linearBackground = FunctionFactory::Instance().createFunction( "PoldiSpectrumLinearBackground"); linearBackground->setParameter(0, getProperty("LinearBackgroundParameter")); poldi2DFunction->addFunction(linearBackground); } }
/** * Create a function from an expression. * @param expr :: The input expression * @param parentAttributes :: An output map filled with the attribute name & values of the parent function * @return A pointer to the created function */ IFunction_sptr FunctionFactoryImpl::createSimple(const Expression& expr, std::map<std::string,std::string>& parentAttributes)const { if (expr.name() == "=" && expr.size() > 1) { return createFunction(expr.terms()[1].name()); } if (expr.name() != "," || expr.size() == 0) { inputError(expr.str()); } const std::vector<Expression>& terms = expr.terms(); std::vector<Expression>::const_iterator term = terms.begin(); if (term->name() != "=") inputError(expr.str()); if (term->terms()[0].name() != "name" && term->terms()[0].name() != "composite") { throw std::invalid_argument("Function name must be defined before its parameters"); } std::string fnName = term->terms()[1].name(); IFunction_sptr fun = createFunction(fnName); for(++term;term!=terms.end();++term) {// loop over function's parameters/attributes if (term->name() != "=") inputError(expr.str()); std::string parName = term->terms()[0].name(); std::string parValue = term->terms()[1].str(); if (fun->hasAttribute(parName)) {// set attribute if (parValue.size() > 1 && parValue[0] == '"') {// remove the double quotes parValue = parValue.substr(1,parValue.size()-2); } IFunction::Attribute att = fun->getAttribute(parName); att.fromString(parValue); fun->setAttribute(parName,att); } else if (parName.size() >= 10 && parName.substr(0,10) == "constraint") {// or it can be a list of constraints addConstraints(fun,(*term)[1]); } else if (parName == "ties") { addTies(fun,(*term)[1]); } else if (!parName.empty() && parName[0] == '$') { parName.erase(0,1); parentAttributes[parName] = parValue; } else {// set initial parameter value fun->setParameter(parName,atof(parValue.c_str())); } }// for term fun->applyTies(); return fun; }
/// Returns a vector of peak collections extracted from the function std::vector<PoldiPeakCollection_sptr> PoldiFitPeaks2D::getCountPeakCollections( const API::IFunction_sptr &fitFunction) { Poldi2DFunction_sptr poldiFunction = boost::dynamic_pointer_cast<Poldi2DFunction>(fitFunction); if (!poldiFunction) { throw std::runtime_error("Can only extract peaks from Poldi2DFunction."); } // Covariance matrix - needs to be assigned to the member functions for error // calculation boost::shared_ptr<const Kernel::DblMatrix> covarianceMatrix = poldiFunction->getCovarianceMatrix(); std::vector<PoldiPeakCollection_sptr> countPeakCollections; size_t offset = 0; for (size_t i = 0; i < poldiFunction->nFunctions(); ++i) { IFunction_sptr localFunction = poldiFunction->getFunction(i); size_t nLocalParams = localFunction->nParams(); // Assign local covariance matrix. boost::shared_ptr<Kernel::DblMatrix> localCov = getLocalCovarianceMatrix(covarianceMatrix, offset, nLocalParams); localFunction->setCovarianceMatrix(localCov); try { PoldiPeakCollection_sptr normalizedPeaks = getPeakCollectionFromFunction(localFunction); countPeakCollections.push_back(getCountPeakCollection(normalizedPeaks)); } catch (const std::invalid_argument &) { // not a Poldi2DFunction - skip (the background functions) } offset += nLocalParams; } return countPeakCollections; }
/** 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; }
/** * @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 ""; }