"examples/hello/callback/helloCallback.cpp" did not exist on "c2dc375d5a622a0f95a2d913faad71cf77d069b3"
Newer
Older
#include "MantidAPI/FunctionFactory.h"
#include "MantidAPI/IFunction.h"
Roman Tolchenov
committed
#include "MantidAPI/CompositeFunction.h"
#include "MantidAPI/MultiDomainFunction.h"
Roman Tolchenov
committed
#include "MantidAPI/Expression.h"
#include "MantidAPI/ConstraintFactory.h"
#include "MantidAPI/IConstraint.h"
#include "MantidAPI/Workspace.h"
#include "MantidAPI/AnalysisDataService.h"
Gigg, Martyn Anthony
committed
#include "MantidKernel/LibraryManager.h"
#include <MantidKernel/StringTokenizer.h>
#include <boost/lexical_cast.hpp>
#include <sstream>
Roman Tolchenov
committed
namespace Mantid {
namespace API {
FunctionFactoryImpl::FunctionFactoryImpl()
: Kernel::DynamicFactory<IFunction>() {
// we need to make sure the library manager has been loaded before we
// are constructed so that it is destroyed after us and thus does
// not close any loaded DLLs with loaded algorithms in them
Mantid::Kernel::LibraryManager::Instance();
}
IFunction_sptr
FunctionFactoryImpl::createFunction(const std::string &type) const {
IFunction_sptr fun = create(type);
fun->initialize();
return fun;
}
Roman Tolchenov
committed
/**Creates an instance of a function
* @param input :: An input string which defines the function and initial values
* for the parameters.
* Parameters of different functions are separated by ';'. Parameters of the
* same function
* are separated by ','. parameterName=value pairs are used to set a parameter
* value. For each function
* "name" parameter must be set to a function name. E.g.
* input = "name=LinearBackground,A0=0,A1=1; name = Gaussian,
* PeakCentre=10.,Sigma=1"
* @return A pointer to the created function
*/
IFunction_sptr
FunctionFactoryImpl::createInitialized(const std::string &input) const {
Expression expr;
try {
expr.parse(input);
} catch (Expression::ParsingError &e) {
inputError(input + "\n " + e.what());
} catch (...) {
inputError(input);
}
Roman Tolchenov
committed
const Expression &e = expr.bracketsRemoved();
std::map<std::string, std::string> parentAttributes;
if (e.name() == ";") {
IFunction_sptr fun = createComposite(e, parentAttributes);
if (!fun)
inputError();
return fun;
}
Roman Tolchenov
committed
return createSimple(e, parentAttributes);
}
Roman Tolchenov
committed
/**
* 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());
}
Roman Tolchenov
committed
if (expr.name() != "," || expr.size() == 0) {
inputError(expr.str());
}
Roman Tolchenov
committed
const std::vector<Expression> &terms = expr.terms();
auto term = terms.cbegin();
Roman Tolchenov
committed
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();
Peterson, Peter
committed
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);
Peterson, Peter
committed
}
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].bracketsRemoved());
addTies(fun, (*term)[1].bracketsRemoved());
} else if (!parName.empty() && parName[0] == '$') {
parName.erase(0, 1);
parentAttributes[parName] = parValue;
} else {
// set initial parameter value
try {
fun->setParameter(parName, boost::lexical_cast<double>(parValue));
} catch (boost::bad_lexical_cast &) {
throw std::runtime_error(
"Error in value of parameter " + parName + ".\n" + parValue +
" cannot be interpreted as a floating point value.");
}
Peterson, Peter
committed
}
Peterson, Peter
committed
fun->applyTies();
return fun;
}
Peterson, Peter
committed
/**
* Create a composite 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
*/
CompositeFunction_sptr FunctionFactoryImpl::createComposite(
const Expression &expr,
std::map<std::string, std::string> &parentAttributes) const {
if (expr.name() != ";")
inputError(expr.str());
Peterson, Peter
committed
if (expr.size() == 0) {
return CompositeFunction_sptr();
}
Peterson, Peter
committed
const std::vector<Expression> &terms = expr.terms();
auto it = terms.cbegin();
const Expression &term = it->bracketsRemoved();
CompositeFunction_sptr cfun;
if (term.name() == "=") {
if (term.terms()[0].name() == "composite") {
cfun = boost::dynamic_pointer_cast<CompositeFunction>(
createFunction(term.terms()[1].name()));
if (!cfun)
inputError(expr.str());
++it;
} else if (term.terms()[0].name() == "name") {
cfun = boost::dynamic_pointer_cast<CompositeFunction>(
createFunction("CompositeFunction"));
if (!cfun)
inputError(expr.str());
} else {
inputError(expr.str());
}
} else if (term.name() == ",") {
auto firstTerm = term.terms().cbegin();
if (firstTerm->name() == "=") {
if (firstTerm->terms()[0].name() == "composite") {
cfun = boost::dynamic_pointer_cast<CompositeFunction>(
createSimple(term, parentAttributes));
if (!cfun)
Peterson, Peter
committed
inputError(expr.str());
++it;
} else if (firstTerm->terms()[0].name() == "name") {
cfun = boost::dynamic_pointer_cast<CompositeFunction>(
createFunction("CompositeFunction"));
if (!cfun)
inputError(expr.str());
} else {
Peterson, Peter
committed
inputError(expr.str());
}
}
} else if (term.name() == ";") {
cfun = boost::dynamic_pointer_cast<CompositeFunction>(
createFunction("CompositeFunction"));
if (!cfun)
inputError(expr.str());
} else {
inputError(expr.str());
}
Peterson, Peter
committed
if (!cfun)
inputError(expr.str());
for (; it != terms.end(); ++it) {
const Expression &term = it->bracketsRemoved();
IFunction_sptr fun;
std::map<std::string, std::string> pAttributes;
if (term.name() == ";") {
fun = createComposite(term, pAttributes);
if (!fun)
continue;
} else {
std::string parName = term[0].name();
if (parName.size() >= 10 && parName.substr(0, 10) == "constraint") {
addConstraints(cfun, term[1].bracketsRemoved());
continue;
} else if (parName == "ties") {
addTies(cfun, term[1].bracketsRemoved());
continue;
} else {
fun = createSimple(term, pAttributes);
Peterson, Peter
committed
}
}
cfun->addFunction(fun);
size_t i = cfun->nFunctions() - 1;
for (auto &pAttribute : pAttributes) {
// Apply parent attributes of the child function to this function. If this
// function doesn't have those attributes, they get passed up the chain to
// this function's parent.
if (cfun->hasLocalAttribute(pAttribute.first)) {
cfun->setLocalAttributeValue(i, pAttribute.first, pAttribute.second);
} else {
parentAttributes[pAttribute.first] = pAttribute.second;
}
Peterson, Peter
committed
}
Peterson, Peter
committed
if (cfun) {
cfun->applyTies();
}
Peterson, Peter
committed
/// Throw an exception
void FunctionFactoryImpl::inputError(const std::string &str) const {
std::string msg("Error in input string to FunctionFactory");
if (!str.empty()) {
msg += "\n" + str;
}
throw std::invalid_argument(msg);
}
Peterson, Peter
committed
/**
* Add constraints to the created function
* @param fun :: The function
* @param expr :: The constraint expression. The expression name must be either
* a single constraint
* expression such as "0 < Sigma < 1" or a list of constraint expressions
* separated by commas ','
* and enclosed in brackets "(...)" .
*/
void FunctionFactoryImpl::addConstraints(IFunction_sptr fun,
const Expression &expr) const {
if (expr.name() == ",") {
for (const auto &constraint : expr) {
addConstraint(fun, constraint);
Peterson, Peter
committed
}
} else {
addConstraint(fun, expr);
}
}
/**
* Add a constraints to the function
* @param fun :: The function
* @param expr :: The constraint expression.
*/
void FunctionFactoryImpl::addConstraint(IFunction_sptr fun,
const Expression &expr) const {
IConstraint *c =
ConstraintFactory::Instance().createInitialized(fun.get(), expr);
fun->addConstraint(c);
}
Peterson, Peter
committed
/**
* @param fun :: The function
* @param expr :: The tie expression: either parName = TieString or a list
* of name = string pairs
*/
void FunctionFactoryImpl::addTies(IFunction_sptr fun,
const Expression &expr) const {
if (expr.name() == "=") {
addTie(fun, expr);
} else if (expr.name() == ",") {
for (const auto &constraint : expr) {
addTie(fun, constraint);
}
/**
* @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
// 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);
}
}
}
void FunctionFactoryImpl::subscribe(
const std::string &className, AbstractFactory *pAbstractFactory,
Kernel::DynamicFactory<IFunction>::SubscribeAction replace) {
// Clear the cache, then do all the work in the base class method
m_cachedFunctionNames.clear();
Kernel::DynamicFactory<IFunction>::subscribe(className, pAbstractFactory,
replace);
}
void FunctionFactoryImpl::unsubscribe(const std::string &className) {
// Clear the cache, then do all the work in the base class method
m_cachedFunctionNames.clear();
Kernel::DynamicFactory<IFunction>::unsubscribe(className);
}
} // namespace Mantid