Newer
Older
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
Roman Tolchenov
committed
#include "MantidAPI/CompositeFunction.h"
#include "MantidAPI/ParameterTie.h"
#include "MantidAPI/IConstraint.h"
#include "MantidAPI/FunctionFactory.h"
#include "MantidKernel/Exception.h"
#include "MantidKernel/Logger.h"
Peterson, Peter
committed
#include <boost/lexical_cast.hpp>
#include <boost/shared_array.hpp>
#include <sstream>
Roman Tolchenov
committed
#include <algorithm>
namespace Mantid {
namespace API {
namespace {
/// static logger
Kernel::Logger g_log("CompositeFunction");
}
DECLARE_FUNCTION(CompositeFunction)
/// Default constructor
CompositeFunction::CompositeFunction()
: IFunction(), m_nParams(0), m_iConstraintFunction(false) {
declareAttribute("NumDeriv", Attribute(false));
}
/// Function initialization. Declare function parameters in this method.
Roman Tolchenov
committed
* Writes itself into a string. Functions derived from CompositeFunction must
* override this method with something like this:
* std::string NewFunction::asString()const
* {
* ostr << "composite=" << this->name() << ';';
* // write NewFunction's own attributes and parameters
* ostr << CompositeFunction::asString();
* // write NewFunction's own ties and constraints
* // ostr << ";constraints=(" << ... <<")";
* }
* @return the string representation of the composite function
Roman Tolchenov
committed
*/
std::string CompositeFunction::asString() const {
Roman Tolchenov
committed
std::ostringstream ostr;
if (name() != "CompositeFunction" || nAttributes() > 1 ||
getAttribute("NumDeriv").asBool()) {
std::vector<std::string> attr = this->getAttributeNames();
for (const auto &attName : attr) {
std::string attValue = this->getAttribute(attName).value();
if (!attValue.empty()) {
ostr << ',' << attName << '=' << attValue;
}
}
ostr << ';';
for (size_t i = 0; i < nFunctions(); i++) {
const auto localAttr = this->getLocalAttributeNames();
IFunction_sptr fun = getFunction(i);
bool isComp =
boost::dynamic_pointer_cast<CompositeFunction>(fun) != nullptr;
Roman Tolchenov
committed
ostr << fun->asString();
for (const auto &localAttName : localAttr) {
const std::string localAttValue =
this->getLocalAttribute(i, localAttName).value();
if (!localAttValue.empty()) {
// local attribute names are prefixed by dollar sign
ostr << ',' << '$' << localAttName << '=' << localAttValue;
}
}
if (isComp)
ostr << ')';
if (i < nFunctions() - 1) {
Roman Tolchenov
committed
ostr << ';';
}
}
std::string ties;
for (size_t i = 0; i < nParams(); i++) {
const ParameterTie *tie = getTie(i);
if (tie) {
IFunction_sptr fun = getFunction(functionIndex(i));
std::string tmp = tie->asString(fun.get());
Roman Tolchenov
committed
tmp = tie->asString(this);
if (!tmp.empty()) {
if (!ties.empty()) {
Roman Tolchenov
committed
ties += ",";
}
ties += tmp;
}
}
}
}
Roman Tolchenov
committed
ostr << ";ties=(" << ties << ")";
Roman Tolchenov
committed
}
return ostr.str();
}
/**
* @param ws A pointer to the workspace being fitted
*/
void CompositeFunction::setWorkspace(boost::shared_ptr<const Workspace> ws) {
// Pass it on to each member
auto iend = m_functions.end();
for (auto it = m_functions.begin(); it != iend; ++it) {
(*it)->setWorkspace(ws);
}
}
/**
* @param workspace :: A workspace to fit to.
* @param wi :: An index of a spectrum to fit to.
* @param startX :: A start of the fitting region.
* @param endX :: An end of the fitting region.
*/
void CompositeFunction::setMatrixWorkspace(
boost::shared_ptr<const MatrixWorkspace> workspace, size_t wi,
double startX, double endX) {
for (size_t iFun = 0; iFun < nFunctions(); ++iFun) {
m_functions[iFun]->setMatrixWorkspace(workspace, wi, startX, endX);
}
* @param domain :: An instance of FunctionDomain with the function arguments.
* @param values :: A FunctionValues instance for storing the calculated
* values.
*/
void CompositeFunction::function(const FunctionDomain &domain,
FunctionValues &values) const {
FunctionValues tmp(domain);
for (size_t iFun = 0; iFun < nFunctions(); ++iFun) {
m_functions[iFun]->function(domain, tmp);
values += tmp;
}
}
/**
* Derivatives of function with respect to active parameters
* @param domain :: Function domain to get the arguments from.
* @param jacobian :: A Jacobian to store the derivatives.
*/
void CompositeFunction::functionDeriv(const FunctionDomain &domain,
Jacobian &jacobian) {
if (getAttribute("NumDeriv").asBool()) {
calNumericalDeriv(domain, jacobian);
} else {
for (size_t iFun = 0; iFun < nFunctions(); ++iFun) {
PartialJacobian J(&jacobian, paramOffset(iFun));
getFunction(iFun)->functionDeriv(domain, J);
}
}
/** Sets a new value to the i-th parameter.
Janik Zikovsky
committed
* @param i :: The parameter index
* @param value :: The new value
* @param explicitlySet :: A boolean falgging the parameter as explicitly set
* (by user)
void CompositeFunction::setParameter(size_t i, const double &value,
bool explicitlySet) {
Roman Tolchenov
committed
size_t iFun = functionIndex(i);
m_functions[iFun]->setParameter(i - m_paramOffsets[iFun], value,
explicitlySet);
Anders Markvardsen
committed
/** Sets a new description to the i-th parameter.
* @param i :: The parameter index
* @param description :: The new description
*/
void CompositeFunction::setParameterDescription(
size_t i, const std::string &description) {
Roman Tolchenov
committed
size_t iFun = functionIndex(i);
m_functions[iFun]->setParameterDescription(i - m_paramOffsets[iFun],
description);
Anders Markvardsen
committed
}
/** Get the i-th parameter.
Janik Zikovsky
committed
* @param i :: The parameter index
* @return value of the requested parameter
double CompositeFunction::getParameter(size_t i) const {
return m_functions[iFun]->getParameter(i - m_paramOffsets[iFun]);
/**
* Sets a new value to a parameter by name.
Janik Zikovsky
committed
* @param name :: The name of the parameter.
* @param value :: The new value
* @param explicitlySet :: A boolean falgging the parameter as explicitly set
* (by user)
void CompositeFunction::setParameter(const std::string &name,
const double &value, bool explicitlySet) {
Peterson, Peter
committed
std::string pname;
Roman Tolchenov
committed
size_t index;
parseName(name, index, pname);
getFunction(index)->setParameter(pname, value, explicitlySet);
Anders Markvardsen
committed
/**
* Sets a new description to a parameter by name.
* @param name :: The name of the parameter.
* @param description :: The new description
Anders Markvardsen
committed
*/
void CompositeFunction::setParameterDescription(
const std::string &name, const std::string &description) {
Anders Markvardsen
committed
std::string pname;
Roman Tolchenov
committed
size_t index;
parseName(name, index, pname);
getFunction(index)->setParameterDescription(pname, description);
Anders Markvardsen
committed
}
/**
* Parameters by name.
Janik Zikovsky
committed
* @param name :: The name of the parameter.
* @return value of the requested named parameter
double CompositeFunction::getParameter(const std::string &name) const {
Peterson, Peter
committed
std::string pname;
Roman Tolchenov
committed
size_t index;
Roman Tolchenov
committed
return getFunction(index)->getParameter(pname);
}
/// Total number of parameters
size_t CompositeFunction::nParams() const { return m_nParams; }
Janik Zikovsky
committed
* @param name :: The name of a parameter
* @return index of the requested named parameter
size_t CompositeFunction::parameterIndex(const std::string &name) const {
Peterson, Peter
committed
std::string pname;
Roman Tolchenov
committed
size_t index;
Russell Taylor
committed
return getFunction(index)->parameterIndex(pname) + m_paramOffsets[index];
Janik Zikovsky
committed
/// @param i :: The index
std::string CompositeFunction::parameterName(size_t i) const {
Roman Tolchenov
committed
size_t iFun = functionIndex(i);
std::ostringstream ostr;
ostr << 'f' << iFun << '.'
<< m_functions[iFun]->parameterName(i - m_paramOffsets[iFun]);
return ostr.str();
Anders Markvardsen
committed
/// Returns the description of parameter
/// @param i :: The index
/// @return The description of the parameter
std::string CompositeFunction::parameterDescription(size_t i) const {
Roman Tolchenov
committed
size_t iFun = functionIndex(i);
Anders Markvardsen
committed
std::ostringstream ostr;
ostr << m_functions[iFun]->parameterDescription(i - m_paramOffsets[iFun]);
Anders Markvardsen
committed
return ostr.str();
}
* Get the fitting error for a parameter
* @param i :: The index of a parameter
* @return :: the error
*/
double CompositeFunction::getError(size_t i) const {
return m_functions[iFun]->getError(i - m_paramOffsets[iFun]);
* Set the fitting error for a parameter
* @param i :: The index of a parameter
* @param err :: The error value to set
*/
void CompositeFunction::setError(size_t i, double err) {
m_functions[iFun]->setError(i - m_paramOffsets[iFun], err);
/// Value of i-th active parameter. Override this method to make fitted
/// parameters different from the declared
double CompositeFunction::activeParameter(size_t i) const {
size_t iFun = functionIndex(i);
return m_functions[iFun]->activeParameter(i - m_paramOffsets[iFun]);
/// Set new value of i-th active parameter. Override this method to make fitted
/// parameters different from the declared
void CompositeFunction::setActiveParameter(size_t i, double value) {
size_t iFun = functionIndex(i);
m_functions[iFun]->setActiveParameter(i - m_paramOffsets[iFun], value);
}
/// Returns the name of active parameter i
std::string CompositeFunction::nameOfActive(size_t i) const {
size_t iFun = functionIndex(i);
std::ostringstream ostr;
ostr << 'f' << iFun << '.'
<< m_functions[iFun]->nameOfActive(i - m_paramOffsets[iFun]);
Anders Markvardsen
committed
return ostr.str();
}
/// Returns the description of active parameter i
std::string CompositeFunction::descriptionOfActive(size_t i) const {
size_t iFun = functionIndex(i);
Anders Markvardsen
committed
std::ostringstream ostr;
ostr << m_functions[iFun]->descriptionOfActive(i - m_paramOffsets[iFun]);
return ostr.str();
/**
* query to see in the function is active
* @param i :: The index of a declared parameter
* @return true if parameter i is active
*/
bool CompositeFunction::isActive(size_t i) const {
size_t iFun = functionIndex(i);
return m_functions[iFun]->isActive(i - m_paramOffsets[iFun]);
* query to see in the function is active
Janik Zikovsky
committed
* @param i :: The index of a declared parameter
* @return true if parameter i is active
bool CompositeFunction::isFixed(size_t i) const {
Roman Tolchenov
committed
size_t iFun = functionIndex(i);
return m_functions[iFun]->isFixed(i - m_paramOffsets[iFun]);
Janik Zikovsky
committed
* @param i :: A declared parameter index to be removed from active
void CompositeFunction::fix(size_t i) {
Roman Tolchenov
committed
size_t iFun = functionIndex(i);
m_functions[iFun]->fix(i - m_paramOffsets[iFun]);
Roman Tolchenov
committed
/** Makes a parameter active again. It doesn't change the parameter's tie.
Janik Zikovsky
committed
* @param i :: A declared parameter index to be restored to active
Roman Tolchenov
committed
*/
void CompositeFunction::unfix(size_t i) {
Roman Tolchenov
committed
size_t iFun = functionIndex(i);
m_functions[iFun]->unfix(i - m_paramOffsets[iFun]);
Roman Tolchenov
committed
}
/** Makes sure that the function is consistent.
void CompositeFunction::checkFunction() {
m_nParams = 0;
m_paramOffsets.clear();
m_IFunction.clear();
std::vector<IFunction_sptr> functions(m_functions.begin(), m_functions.end());
CompositeFunction_sptr cf =
boost::dynamic_pointer_cast<CompositeFunction>(f);
if (cf)
cf->checkFunction();
* Remove all member functions
*/
void CompositeFunction::clear() {
m_nParams = 0;
m_paramOffsets.clear();
m_IFunction.clear();
m_functions.clear();
}
Janik Zikovsky
committed
* @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();
m_paramOffsets.push_back(m_nParams);
m_nParams += f->nParams();
}
Roman Tolchenov
committed
return m_functions.size() - 1;
Roman Tolchenov
committed
/** Remove a function
Janik Zikovsky
committed
* @param i :: The index of the function to remove
Roman Tolchenov
committed
*/
void CompositeFunction::removeFunction(size_t i) {
if (i >= nFunctions())
Roman Tolchenov
committed
throw std::out_of_range("Function index out of range.");
IFunction_sptr fun = getFunction(i);
Roman Tolchenov
committed
Roman Tolchenov
committed
size_t dnp = fun->nParams();
Roman Tolchenov
committed
for (size_t j = 0; j < nParams();) {
ParameterTie *tie = getTie(j);
if (tie && tie->findParametersOf(fun.get())) {
Roman Tolchenov
committed
removeTie(j);
Roman Tolchenov
committed
j++;
}
}
// Shift down the function indeces for parameters
for (auto it = m_IFunction.begin(); it != m_IFunction.end();) {
Roman Tolchenov
committed
it = m_IFunction.erase(it);
Roman Tolchenov
committed
*it -= 1;
}
Roman Tolchenov
committed
}
}
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++) {
Roman Tolchenov
committed
m_paramOffsets[j] -= dnp;
}
m_paramOffsets.erase(m_paramOffsets.begin() + i);
Roman Tolchenov
committed
m_functions.erase(m_functions.begin() + i);
Roman Tolchenov
committed
}
Roman Tolchenov
committed
/** Replace a function with a new one. The old function is deleted.
* The new function must have already its workspace set.
Janik Zikovsky
committed
* @param f_old :: The pointer to the function to replace. If it's not
Roman Tolchenov
committed
* a member of this composite function nothing happens
Janik Zikovsky
committed
* @param f_new :: A pointer to the new function
Roman Tolchenov
committed
*/
void CompositeFunction::replaceFunctionPtr(const IFunction_sptr f_old,
IFunction_sptr f_new) {
std::vector<IFunction_sptr>::const_iterator it =
std::find(m_functions.begin(), m_functions.end(), f_old);
if (it == m_functions.end())
return;
std::vector<IFunction_sptr>::difference_type iFun = it - m_functions.begin();
Roman Tolchenov
committed
}
Roman Tolchenov
committed
/** Replace a function with a new one. The old function is deleted.
Janik Zikovsky
committed
* @param i :: The index of the function to replace
* @param f :: A pointer to the new function
Roman Tolchenov
committed
*/
void CompositeFunction::replaceFunction(size_t i, IFunction_sptr f) {
if (i >= nFunctions())
Roman Tolchenov
committed
throw std::out_of_range("Function index out of range.");
IFunction_sptr fun = getFunction(i);
Roman Tolchenov
committed
size_t np_old = fun->nParams();
Roman Tolchenov
committed
Roman Tolchenov
committed
size_t np_new = f->nParams();
Roman Tolchenov
committed
// Modify function indeces: The new function may have different number of
// parameters
Roman Tolchenov
committed
{
auto itFun = std::find(m_IFunction.begin(), m_IFunction.end(), i);
if (itFun != m_IFunction.end()) // functions must have at least 1 parameter
Roman Tolchenov
committed
{
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
Roman Tolchenov
committed
{
itFun = std::find_if(m_IFunction.begin(), m_IFunction.end(),
std::bind2nd(std::greater<size_t>(), i));
m_IFunction.insert(itFun, np_new, i);
Roman Tolchenov
committed
}
Roman Tolchenov
committed
}
Roman Tolchenov
committed
size_t dnp = np_new - np_old;
Roman Tolchenov
committed
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++) {
Roman Tolchenov
committed
m_paramOffsets[j] += dnp;
}
m_functions[i] = f;
}
Janik Zikovsky
committed
* @param i :: The index of the function
* @return function at the requested index
IFunction_sptr CompositeFunction::getFunction(std::size_t i) const {
if (i >= nFunctions()) {
throw std::out_of_range("Function index out of range.");
Roman Tolchenov
committed
}
/**
* Get the index of the function to which parameter i belongs
Janik Zikovsky
committed
* @param i :: The parameter index
* @return function index of the requested parameter
size_t CompositeFunction::functionIndex(std::size_t i) const {
if (i >= nParams()) {
throw std::out_of_range("Function parameter index out of range.");
Roman Tolchenov
committed
}
return m_IFunction[i];
* @param varName :: The variable name which may contain function index (
* [f<index.>]name )
Roman Tolchenov
committed
* @param index :: Receives function index or throws std::invalid_argument
Janik Zikovsky
committed
* @param name :: Receives the parameter name
void CompositeFunction::parseName(const std::string &varName, size_t &index,
std::string &name) {
Peterson, Peter
committed
size_t i = varName.find('.');
Roman Tolchenov
committed
throw std::invalid_argument("Parameter " + varName + " not found.");
Peterson, Peter
committed
if (varName[0] != 'f')
throw std::invalid_argument(
"External function parameter name must start with 'f'");
Peterson, Peter
committed
std::string sindex = varName.substr(1, i - 1);
Peterson, Peter
committed
index = boost::lexical_cast<int>(sindex);
if (i == varName.size() - 1)
throw std::invalid_argument("Name cannot be empty");
Peterson, Peter
committed
}
Roman Tolchenov
committed
/** Returns the index of parameter i as it declared in its function
Janik Zikovsky
committed
* @param i :: The parameter index
Roman Tolchenov
committed
* @return The local index of the parameter
*/
size_t CompositeFunction::parameterLocalIndex(size_t i) const {
Roman Tolchenov
committed
size_t iFun = functionIndex(i);
Roman Tolchenov
committed
return i - m_paramOffsets[iFun];
}
/** Returns the name of parameter i as it declared in its function
Janik Zikovsky
committed
* @param i :: The parameter index
* @return The pure parameter name (without the function identifier f#.)
*/
std::string CompositeFunction::parameterLocalName(size_t i) const {
Roman Tolchenov
committed
size_t iFun = functionIndex(i);
return m_functions[iFun]->parameterName(i - m_paramOffsets[iFun]);
Roman Tolchenov
committed
/**
Roman Tolchenov
committed
* Apply the ties.
Roman Tolchenov
committed
*/
void CompositeFunction::applyTies() {
for (size_t i = 0; i < nFunctions(); i++) {
Roman Tolchenov
committed
getFunction(i)->applyTies();
}
}
/**
Roman Tolchenov
committed
*/
void CompositeFunction::clearTies() {
for (size_t i = 0; i < nFunctions(); i++) {
Roman Tolchenov
committed
getFunction(i)->clearTies();
}
}
/** Removes i-th parameter's tie if it is tied or does nothing.
Janik Zikovsky
committed
* @param i :: The index of the tied parameter.
Roman Tolchenov
committed
* @return True if successfull
*/
bool CompositeFunction::removeTie(size_t i) {
Roman Tolchenov
committed
size_t iFun = functionIndex(i);
bool res = m_functions[iFun]->removeTie(i - m_paramOffsets[iFun]);
Roman Tolchenov
committed
return res;
}
/** Get the tie of i-th parameter
Janik Zikovsky
committed
* @param i :: The parameter index
* @return A pointer to the tie.
Roman Tolchenov
committed
*/
ParameterTie *CompositeFunction::getTie(size_t i) const {
Roman Tolchenov
committed
size_t iFun = functionIndex(i);
return m_functions[iFun]->getTie(i - m_paramOffsets[iFun]);
Roman Tolchenov
committed
}
/**
* Attaches a tie to this function. The attached tie is owned by the function.
Janik Zikovsky
committed
* @param tie :: A pointer to a new tie
Roman Tolchenov
committed
*/
void CompositeFunction::addTie(ParameterTie *tie) {
Roman Tolchenov
committed
size_t i = getParameterIndex(*tie);
size_t iFun = functionIndex(i);
Roman Tolchenov
committed
m_functions[iFun]->addTie(tie);
}
/**
* Declare a new parameter. To used in the implementation'c constructor.
Janik Zikovsky
committed
* @param name :: The parameter name.
* @param initValue :: The initial value for the parameter
* @param description :: Parameter documentation
Roman Tolchenov
committed
*/
void CompositeFunction::declareParameter(const std::string &name,
double initValue,
const std::string &description) {
(void)name; // Avoid compiler warning
(void)initValue; // Avoid compiler warning
(void)description; // Avoid compiler warning
throw Kernel::Exception::NotImplementedError(
"CompositeFunction cannot not have its own parameters.");
Roman Tolchenov
committed
}
/** Add a constraint
Janik Zikovsky
committed
* @param ic :: Pointer to a constraint.
Roman Tolchenov
committed
*/
void CompositeFunction::addConstraint(IConstraint *ic) {
Roman Tolchenov
committed
size_t i = getParameterIndex(*ic);
size_t iFun = functionIndex(i);
getFunction(iFun)->addConstraint(ic);
Roman Tolchenov
committed
}
/**
* Prepare the function for a fit.
*/
void CompositeFunction::setUpForFit() {
// set up the member functions
for (size_t i = 0; i < nFunctions(); i++) {
getFunction(i)->setUpForFit();
// unfortuately the code below breaks some system tests (IRISFuryAndFuryFit)
// it looks as if using numeric derivatives can give different fit results
// to fit with analytical ones
//
// if parameters have non-constant ties enable numerical derivatives
// for(size_t i = 0; i < nParams(); ++i)
//{
// ParameterTie* tie = getTie( i );
// if ( tie && !tie->isConstant() )
// {
// useNumericDerivatives( true );
// break;
// }
//}
// instead of automatically switching to numeric derivatives
// log a warning about a danger of not using it
if (!getAttribute("NumDeriv").asBool()) {
for (size_t i = 0; i < nParams(); ++i) {
ParameterTie *tie = getTie(i);
if (tie && !tie->isConstant()) {
g_log.warning() << "Numeric derivatives should be used when "
"non-constant ties defined.\n";
break;
}
Anders Markvardsen
committed
}
}
Janik Zikovsky
committed
/// @param i :: the index
IConstraint *CompositeFunction::getConstraint(size_t i) const {
Roman Tolchenov
committed
size_t iFun = functionIndex(i);
return m_functions[iFun]->getConstraint(i - m_paramOffsets[iFun]);
/** Remove a constraint
Janik Zikovsky
committed
* @param parName :: The name of a parameter which constarint to remove.
void CompositeFunction::removeConstraint(const std::string &parName) {
Roman Tolchenov
committed
size_t iPar = parameterIndex(parName);
size_t iFun = functionIndex(iPar);
getFunction(iFun)->removeConstraint(parameterLocalName(iPar));
}
/** Checks if a constraint has been explicitly set
Janik Zikovsky
committed
* @param i :: The parameter index
* @return true if the function is explicitly set
bool CompositeFunction::isExplicitlySet(size_t i) const {
Roman Tolchenov
committed
size_t iFun = functionIndex(i);
return m_functions[iFun]->isExplicitlySet(i - m_paramOffsets[iFun]);
}
* Returns the index of parameter if the ref points to one of the member
* function
Janik Zikovsky
committed
* @param ref :: A reference to a parameter
Roman Tolchenov
committed
* @return Parameter index or number of nParams() if parameter not found
size_t
CompositeFunction::getParameterIndex(const ParameterReference &ref) const {
if (ref.getFunction() == this && ref.getIndex() < nParams()) {
Roman Tolchenov
committed
return ref.getIndex();
for (size_t iFun = 0; iFun < nFunctions(); iFun++) {
IFunction_sptr fun = getFunction(iFun);
Roman Tolchenov
committed
size_t iLocalIndex = fun->getParameterIndex(ref);
if (iLocalIndex < fun->nParams()) {
Roman Tolchenov
committed
return m_paramOffsets[iFun] + iLocalIndex;
}
}
Roman Tolchenov
committed
return nParams();
* Returns the shrared pointer to the function conataining a parameter
Janik Zikovsky
committed
* @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();
}
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
/// Get number of domains required by this function
size_t CompositeFunction::getNumberDomains() const {
auto n = nFunctions();
if (n == 0) {
return 1;
}
size_t nd = getFunction(0)->getNumberDomains();
for (size_t iFun = 1; iFun < n; ++iFun) {
if (getFunction(0)->getNumberDomains() != nd) {
throw std::runtime_error("CompositeFunction has members with "
"inconsistent domain numbers.");
}
}
return nd;
}
/// Split this function (if needed) into a list of independent functions.
/// The number of functions must be the number of domains this function is
/// working on (== getNumberDomains()). The result of evaluation of the
/// created functions on their domains must be the same as if this function
/// was evaluated on the composition of those domains.
std::vector<IFunction_sptr> CompositeFunction::createEquivalentFunctions() const {
auto nd = getNumberDomains();
if (nd == 1) {
return std::vector<IFunction_sptr>(
1, FunctionFactory::Instance().createInitialized(asString()));
}
auto nf = nFunctions();
std::vector<std::vector<IFunction_sptr>> equiv;
equiv.reserve(nf);
for(size_t i = 0; i < nf; ++i) {
equiv.push_back(getFunction(i)->createEquivalentFunctions());
}
std::vector<IFunction_sptr> funs;
funs.reserve(nd);
for(size_t i = 0; i < nd; ++i) {
auto comp = new CompositeFunction;
funs.push_back(IFunction_sptr(comp));
for(size_t j = 0; j < nf; ++j) {
comp->addFunction(equiv[j][i]);
}
}
return funs;
}
} // namespace API
} // namespace Mantid