Skip to content

Commit

Permalink
Re #4158. Made MultiDomainFunction initialization in FunctionFactory.
Browse files Browse the repository at this point in the history
  • Loading branch information
mantid-roman committed Apr 2, 2012
1 parent c542f00 commit a02b074
Show file tree
Hide file tree
Showing 10 changed files with 283 additions and 38 deletions.
25 changes: 23 additions & 2 deletions Code/Mantid/Framework/API/inc/MantidAPI/CompositeFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
//----------------------------------------------------------------------
#include "MantidAPI/IFunction.h"
#include "MantidAPI/Jacobian.h"

#include <boost/shared_array.hpp>
#include <map>

namespace Mantid
{
Expand Down Expand Up @@ -132,7 +134,6 @@ class MANTID_API_DLL CompositeFunction : public virtual IFunction
/// Remove a constraint
void removeConstraint(const std::string& parName);


/* CompositeFunction own methods */

/// Add a function at the back of the internal function list
Expand All @@ -158,6 +159,27 @@ class MANTID_API_DLL CompositeFunction : public virtual IFunction
/// Check the function.
void checkFunction();

/// Returns the number of attributes associated with the function
virtual size_t nLocalAttributes()const {return 0;}
/// Returns a list of attribute names
virtual std::vector<std::string> getLocalAttributeNames()const {return std::vector<std::string>();}
/// Return a value of attribute attName
virtual Attribute getLocalAttribute(size_t i, const std::string& attName)const
{
(void)i;
throw std::invalid_argument("Attribute "+attName+" not found in function "+this->name());
}
/// Set a value to attribute attName
virtual void setLocalAttribute(size_t i, const std::string& attName,const Attribute& )
{
(void)i;
throw std::invalid_argument("Attribute "+attName+" not found in function "+this->name());
}
/// Check if attribute attName exists
virtual bool hasLocalAttribute(const std::string&)const {return false;}
template<typename T>
void setLocalAttributeValue(size_t i, const std::string& attName,const T& value){setLocalAttribute(i,attName,Attribute(value));}

protected:
/// Function initialization. Declare function parameters in this method.
void init();
Expand All @@ -184,7 +206,6 @@ class MANTID_API_DLL CompositeFunction : public virtual IFunction
size_t m_nParams;
/// Function counter to be used in nextConstraint
mutable size_t m_iConstraintFunction;

};

///shared pointer to the composite function base class
Expand Down
10 changes: 8 additions & 2 deletions Code/Mantid/Framework/API/inc/MantidAPI/FunctionFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,15 @@ namespace API
using Kernel::DynamicFactory<IFunction>::createUnwrapped;

/// Create a simple function
boost::shared_ptr<IFunction> createSimple(const Expression& expr)const;
boost::shared_ptr<IFunction> createSimple(
const Expression& expr,
std::map<std::string,std::string>& parentAttributes
)const;
/// Create a composite function
boost::shared_ptr<CompositeFunction> createComposite(const Expression& expr)const;
boost::shared_ptr<CompositeFunction> createComposite(
const Expression& expr,
std::map<std::string,std::string>& parentAttributes
)const;
///Creates an instance of a function
boost::shared_ptr<IFunction> createFitFunction(const Expression& expr) const;

Expand Down
2 changes: 2 additions & 0 deletions Code/Mantid/Framework/API/inc/MantidAPI/IFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ class MANTID_API_DLL IFunction
class MANTID_API_DLL Attribute
{
public:
/// Create empty string attribute
explicit Attribute():m_data(""), m_quoteValue(false) {}
/// Create string attribute
explicit Attribute(const std::string& str, bool quoteValue=false):m_data(str), m_quoteValue(quoteValue) {}
/// Create int attribute
Expand Down
16 changes: 16 additions & 0 deletions Code/Mantid/Framework/API/inc/MantidAPI/MultiDomainFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ class MANTID_API_DLL MultiDomainFunction : public CompositeFunction
/// Constructor
MultiDomainFunction():m_nDomains(0),m_maxIndex(0){}

/// Returns the function's name
virtual std::string name()const {return "MultiDomainFunction";}
/// Function you want to fit to.
/// @param domain :: The buffer for writing the calculated values. Must be big enough to accept dataSize() values
virtual void function(const FunctionDomain& domain, FunctionValues& values)const;
Expand All @@ -60,11 +62,25 @@ class MANTID_API_DLL MultiDomainFunction : public CompositeFunction

/// Clear all domain indices
void clearDomainIndices();

/// Returns the number of attributes associated with the function
virtual size_t nLocalAttributes()const {return 1;}
/// Returns a list of attribute names
virtual std::vector<std::string> getLocalAttributeNames()const {return std::vector<std::string>(1,"domains");}
/// Return a value of attribute attName
virtual Attribute getLocalAttribute(size_t i, const std::string& attName)const;
/// Set a value to attribute attName
virtual void setLocalAttribute(size_t i, const std::string& attName,const Attribute& );
/// Check if attribute attName exists
virtual bool hasLocalAttribute(const std::string& attName)const {return attName == "domains";}

protected:

/// Counts number of the domains
void countNumberOfDomains();
void countValueOffsets(const CompositeDomain& domain)const;
void getFunctionDomains(size_t i, const CompositeDomain& cd, std::vector<size_t>& domains)const;

/// Domain index map: finction -> domain
std::map<size_t, std::vector<size_t> > m_domains;
/// Number of domains this MultiDomainFunction operates on. == number of different values in m_domains
Expand Down
1 change: 0 additions & 1 deletion Code/Mantid/Framework/API/src/CompositeFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,5 @@ IFunction_sptr CompositeFunction::getContainingFunction(const ParameterReference
return IFunction_sptr();
}


} // namespace API
} // namespace Mantid
28 changes: 20 additions & 8 deletions Code/Mantid/Framework/API/src/FunctionFactory.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "MantidAPI/FunctionFactory.h"
#include "MantidAPI/IFunction.h"
#include "MantidAPI/CompositeFunction.h"
#include "MantidAPI/MultiDomainFunction.h"
#include "MantidAPI/Expression.h"
#include "MantidAPI/ConstraintFactory.h"
#include "MantidAPI/IConstraint.h"
Expand Down Expand Up @@ -59,15 +60,15 @@ namespace Mantid
}

const Expression& e = expr.bracketsRemoved();

std::map<std::string,std::string> parentAttributes;
if (e.name() == ";")
{
IFunction_sptr fun = createComposite(e);
IFunction_sptr fun = createComposite(e,parentAttributes);
if (!fun) inputError();
return fun;
}

return createSimple(e);
return createSimple(e,parentAttributes);

}

Expand All @@ -76,7 +77,7 @@ namespace Mantid
* @param expr :: The input expression
* @return A pointer to the created function
*/
IFunction_sptr FunctionFactoryImpl::createSimple(const Expression& expr)const
IFunction_sptr FunctionFactoryImpl::createSimple(const Expression& expr, std::map<std::string,std::string>& parentAttributes)const
{
if (expr.name() == "=" && expr.size() > 1)
{
Expand Down Expand Up @@ -122,6 +123,11 @@ namespace Mantid
{
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()));
Expand All @@ -136,7 +142,7 @@ namespace Mantid
* @param expr :: The input expression
* @return A pointer to the created function
*/
CompositeFunction_sptr FunctionFactoryImpl::createComposite(const Expression& expr)const
CompositeFunction_sptr FunctionFactoryImpl::createComposite(const Expression& expr, std::map<std::string,std::string>& parentAttributes)const
{
if (expr.name() != ";") inputError(expr.str());

Expand Down Expand Up @@ -175,7 +181,7 @@ namespace Mantid
{
if (firstTerm->terms()[0].name() == "composite")
{
cfun = boost::dynamic_pointer_cast<CompositeFunction>(createSimple(term));
cfun = boost::dynamic_pointer_cast<CompositeFunction>(createSimple(term,parentAttributes));
if (!cfun) inputError(expr.str());
++it;
}
Expand Down Expand Up @@ -204,9 +210,10 @@ namespace Mantid
{
const Expression& term = it->bracketsRemoved();
IFunction_sptr fun;
std::map<std::string,std::string> pAttributes;
if (term.name() == ";")
{
fun = createComposite(term);
fun = createComposite(term,pAttributes);
if (!fun) continue;
}
else
Expand All @@ -225,10 +232,15 @@ namespace Mantid
}
else
{
fun = createSimple(term);
fun = createSimple(term,pAttributes);
}
}
cfun->addFunction(fun);
size_t i = cfun->nFunctions() - 1;
for(auto att = pAttributes.begin(); att != pAttributes.end(); ++att)
{
cfun->setLocalAttributeValue(i,att->first,att->second);
}
}

return cfun;
Expand Down
128 changes: 104 additions & 24 deletions Code/Mantid/Framework/API/src/MultiDomainFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
//----------------------------------------------------------------------
#include "MantidAPI/MultiDomainFunction.h"
#include "MantidAPI/CompositeDomain.h"
#include "MantidAPI/FunctionFactory.h"
#include "MantidAPI/Expression.h"

#include <boost/lexical_cast.hpp>
#include <set>
Expand All @@ -12,6 +14,8 @@ namespace Mantid
namespace API
{

DECLARE_FUNCTION(MultiDomainFunction)

/**
* Associate a member function and a domain. The function will only be applied
* to this domain.
Expand Down Expand Up @@ -74,6 +78,24 @@ namespace API
countNumberOfDomains();
}

/**
* Populates a vector with domain indices assigned to function i.
*/
void MultiDomainFunction::getFunctionDomains(size_t i, const CompositeDomain& cd, std::vector<size_t>& domains)const
{
auto it = m_domains.find(i);
if (it == m_domains.end())
{// apply to all domains
domains.resize(cd.getNParts());
size_t i = 0;
std::generate(domains.begin(),domains.end(),[&i]()->size_t{return i++;});
}
else
{// apply to selected domains
domains.assign(it->second.begin(),it->second.end());
}
}

/// Function you want to fit to.
/// @param domain :: The buffer for writing the calculated values. Must be big enough to accept dataSize() values
void MultiDomainFunction::function(const FunctionDomain& domain, FunctionValues& values)const
Expand All @@ -97,25 +119,15 @@ namespace API
throw std::invalid_argument("MultiDomainFunction: domain and values have different sizes.");
}

countValueOffsets(cd);
// evaluate member functions
values.zeroCalculated();
for(size_t iFun = 0; iFun < nFunctions(); ++iFun)
{
// find the domains member function must be applied to
std::vector<size_t> domains;
auto it = m_domains.find(iFun);
if (it == m_domains.end())
{// apply to all domains
domains.resize(cd.getNParts());
size_t i = 0;
std::generate(domains.begin(),domains.end(),[&i]()->size_t{return i++;});
}
else
{// apply to selected domains
domains.assign(it->second.begin(),it->second.end());
}
getFunctionDomains(iFun, cd, domains);

countValueOffsets(cd);
for(auto i = domains.begin(); i != domains.end(); ++i)
{
const FunctionDomain& d = cd.getDomain(*i);
Expand Down Expand Up @@ -143,24 +155,14 @@ namespace API
") for MultiDomainFunction (max index " + boost::lexical_cast<std::string>(m_maxIndex) + ").");
}

countValueOffsets(cd);
// evaluate member functions derivatives
for(size_t iFun = 0; iFun < nFunctions(); ++iFun)
{
// find the domains member function must be applied to
std::vector<size_t> domains;
auto it = m_domains.find(iFun);
if (it == m_domains.end())
{// apply to all domains
domains.resize(cd.getNParts());
size_t i = 0;
std::generate(domains.begin(),domains.end(),[&i]()->size_t{return i++;});
}
else
{// apply to selected domains
domains.assign(it->second.begin(),it->second.end());
}
getFunctionDomains(iFun, cd, domains);

countValueOffsets(cd);
for(auto i = domains.begin(); i != domains.end(); ++i)
{
const FunctionDomain& d = cd.getDomain(*i);
Expand All @@ -170,5 +172,83 @@ namespace API
}
}

/// Return a value of attribute attName
IFunction::Attribute MultiDomainFunction::getLocalAttribute(size_t i, const std::string& attName)const
{
if (attName != "domains")
{
throw std::invalid_argument("MultiDomainFunction does not have attribute " + attName);
}
if (i >= nFunctions())
{
throw std::out_of_range("Function index is out of range.");
}
auto it = m_domains.find(i);
if (it == m_domains.end())
{
return IFunction::Attribute("All");
}
else if (it->second.size() == 1 && it->second.front() == i)
{
return IFunction::Attribute("i");
}
else if ( !it->second.empty() )
{
std::string out(boost::lexical_cast<std::string>(it->second.front()));
for(auto i = it->second.begin() + 1; i != it->second.end(); ++it)
{
out += "," + boost::lexical_cast<std::string>(*i);
}
return IFunction::Attribute(out);
}
return IFunction::Attribute("");
}

/**
* Set a value to attribute attName
*/
void MultiDomainFunction::setLocalAttribute(size_t i, const std::string& attName,const IFunction::Attribute& att)
{
if (attName != "domains")
{
throw std::invalid_argument("MultiDomainFunction does not have attribute " + attName);
}
if (i >= nFunctions())
{
throw std::out_of_range("Function index is out of range.");
}
std::string value = att.asString();
auto it = m_domains.find(i);

if (value == "All")
{// fit to all domains
if (it != m_domains.end())
{
m_domains.erase(it);
}
return;
}
else if (value == "i")
{// fit to domain with the same index as the function
setDomainIndex(i,i);
return;
}
else if (value.empty())
{// do not fit to any domain
setDomainIndices(i,std::vector<size_t>());
}
// fit to a selection of domains
std::vector<size_t> indx;
Expression list;
list.parse(value);
list.toList();
for(size_t k = 0; k < list.size(); ++k)
{
indx.push_back(boost::lexical_cast<size_t>(list[k].name()));
}
setDomainIndices(i,indx);
}


} // namespace API
} // namespace Mantid

0 comments on commit a02b074

Please sign in to comment.