Skip to content

Commit

Permalink
Added a vector type to the function attributes. Re #7623.
Browse files Browse the repository at this point in the history
Modified the GUI to handle the new type. Created BSpline fitting function which uses the new vector attribute to test it in the GUI.
  • Loading branch information
mantid-roman committed Aug 7, 2013
1 parent 346187f commit 36a3244
Show file tree
Hide file tree
Showing 18 changed files with 1,039 additions and 68 deletions.
5 changes: 3 additions & 2 deletions Code/Mantid/Framework/API/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,9 @@ set ( TEST_FILES
FilePropertyTest.h
FrameworkManagerTest.h
FuncMinimizerFactoryTest.h
FunctionDomainTest.h
FunctionFactoryTest.h
FunctionAttributeTest.h
FunctionDomainTest.h
FunctionFactoryTest.h
FunctionPropertyTest.h
FunctionTest.h
FunctionValuesTest.h
Expand Down
25 changes: 22 additions & 3 deletions Code/Mantid/Framework/API/inc/MantidAPI/IFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ class MANTID_API_DLL IFunction
T operator()(int& i)const{return apply(i);}
/// implements static_visitor's operator() for bool
T operator()(bool& b)const{return apply(b);}
/// implements static_visitor's operator() for vector
T operator()(std::vector<double>& v)const{return apply(v);}
protected:
/// Implement this mathod to access attribute as string
virtual T apply(std::string&)const = 0;
Expand All @@ -161,6 +163,8 @@ class MANTID_API_DLL IFunction
virtual T apply(int&)const = 0;
/// Implement this mathod to access attribute as bool
virtual T apply(bool&)const = 0;
/// Implement this mathod to access attribute as vector
virtual T apply(std::vector<double>&)const = 0;
};

/**
Expand All @@ -180,6 +184,8 @@ class MANTID_API_DLL IFunction
T operator()(int& i)const{return apply(i);}
/// implements static_visitor's operator() for bool
T operator()(bool& b)const{return apply(b);}
/// implements static_visitor's operator() for vector
T operator()(std::vector<double>& v)const{return apply(v);}
protected:
/// Implement this mathod to access attribute as string
virtual T apply(const std::string& str)const = 0;
Expand All @@ -189,6 +195,8 @@ class MANTID_API_DLL IFunction
virtual T apply(const int& i)const = 0;
/// Implement this mathod to access attribute as bool
virtual T apply(const bool& i)const = 0;
/// Implement this mathod to access attribute as vector
virtual T apply(const std::vector<double>&)const = 0;
};

/// Attribute is a non-fitting parameter.
Expand All @@ -207,14 +215,18 @@ class MANTID_API_DLL IFunction
explicit Attribute(const double& d):m_data(d){}
/// Create bool attribute
explicit Attribute(const bool& b):m_data(b){}
/// Create bool attribute
/// Create string attribute
explicit Attribute(const char* c):m_data(std::string(c)), m_quoteValue(false){}
/// Apply an attribute visitor
/// Create vector attribute
explicit Attribute(const std::vector<double>& v):m_data(v){}

/// Apply an attribute visitor
template<typename T>
T apply(AttributeVisitor<T>& v){return boost::apply_visitor(v,m_data);}
/// Apply a const attribute visitor
template<typename T>
T apply(ConstAttributeVisitor<T>& v)const{return boost::apply_visitor(v,m_data);}

/// Returns type of the attribute
std::string type()const;
/// Returns the attribute value as a string
Expand All @@ -231,6 +243,9 @@ class MANTID_API_DLL IFunction
double asDouble()const;
/// Returns bool value if attribute is a bool, throws exception otherwise
bool asBool()const;
/// Returns bool value if attribute is a vector, throws exception otherwise
std::vector<double> asVector()const;

/// Sets new value if attribute is a string
void setString(const std::string& str);
/// Sets new value if attribute is a double
Expand All @@ -239,11 +254,13 @@ class MANTID_API_DLL IFunction
void setInt(const int&);
/// Sets new value if attribute is a bool
void setBool(const bool&);
/// Sets new value if attribute is a vector
void setVector(const std::vector<double>&);
/// Set value from a string.
void fromString(const std::string& str);
private:
/// The data holder as boost variant
mutable boost::variant<std::string,int,double,bool> m_data;
mutable boost::variant< std::string,int,double,bool,std::vector<double> > m_data;
/// Flag indicating if the string value should be returned quoted
bool m_quoteValue;
};
Expand Down Expand Up @@ -402,6 +419,8 @@ class MANTID_API_DLL IFunction
virtual void setAttribute(const std::string& attName,const Attribute& );
/// Check if attribute attName exists
virtual bool hasAttribute(const std::string& attName)const;
/// Set multiple attributes in one call
virtual void setAttributes(const std::map<std::string, API::IFunction::Attribute>& attributes);
/// Set an attribute value
template<typename T>
void setAttributeValue(const std::string& attName,const T& value){setAttribute(attName,Attribute(value));}
Expand Down
38 changes: 31 additions & 7 deletions Code/Mantid/Framework/API/src/FunctionFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,28 +100,41 @@ namespace Mantid
}
std::string fnName = term->terms()[1].name();

// collect all attributes into a map
std::map<std::string, IFunction::Attribute> attributes;
bool doneAttributes = false;

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
{
// set attribute
if ( doneAttributes )
{
throw std::invalid_argument("FunctionFactory: attributes must be set before any other property.");
}
if (parValue.size() > 1 && parValue[0] == '"')
{// remove the double quotes
{
// remove the double quotes
parValue = parValue.substr(1,parValue.size()-2);
}
IFunction::Attribute att = fun->getAttribute(parName);
att.fromString(parValue);
fun->setAttribute(parName,att);
IFunction::Attribute att = fun->getAttribute( parName );
att.fromString( parValue );
attributes[parName] = att;
}
else if (parName.size() >= 10 && parName.substr(0,10) == "constraint")
{// or it can be a list of constraints
{
doneAttributes = true;
// or it can be a list of constraints
addConstraints(fun,(*term)[1]);
}
else if (parName == "ties")
{
doneAttributes = true;
addTies(fun,(*term)[1]);
}
else if (!parName.empty() && parName[0] == '$')
Expand All @@ -130,11 +143,22 @@ namespace Mantid
parentAttributes[parName] = parValue;
}
else
{// set initial parameter value
{
if ( !doneAttributes )
{
fun->setAttributes( attributes );
}
doneAttributes = true;
// set initial parameter value
fun->setParameter(parName,atof(parValue.c_str()));
}
}// for term

if ( !doneAttributes && !attributes.empty() )
{
fun->setAttributes( attributes );
}

fun->applyTies();
return fun;
}
Expand Down
100 changes: 95 additions & 5 deletions Code/Mantid/Framework/API/src/IFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,8 @@ namespace
std::string apply(const double&)const{return "double";}
/// Apply if bool
std::string apply(const bool&)const{return "bool";}
/// Apply if vector
std::string apply(const std::vector<double>&)const{return "std::vector<double>";}
};
}

Expand All @@ -327,7 +329,7 @@ std::string IFunction::Attribute::type()const
namespace
{
/**
* Const attribute visitor returning the type of the attribute
* Const attribute visitor returning the value of the attribute as a string
*/
class AttValue: public IFunction::ConstAttributeVisitor<std::string>
{
Expand All @@ -350,6 +352,21 @@ namespace
std::string apply(const double& d)const{return boost::lexical_cast<std::string>(d);}
/// Apply if bool
std::string apply(const bool& b)const{return b ? "true" : "false";}
/// Apply if vector
std::string apply(const std::vector<double>& v)const
{
std::string res = "(";
if ( v.size() > 0 )
{
for(size_t i = 0; i < v.size()-1; ++i)
{
res += boost::lexical_cast<std::string>( v[i] ) + ",";
}
res += boost::lexical_cast<std::string>( v.back() );
}
res += ")";
return res;
}

private:
/// Flag to quote a string value returned
Expand Down Expand Up @@ -473,7 +490,23 @@ bool IFunction::Attribute::asBool()const
{
throw std::runtime_error("Trying to access a "+type()+" attribute "
"as bool");
}
}
}

/**
* Return the attribute as a bool if it is a vector.
*/
std::vector<double> IFunction::Attribute::asVector() const
{
try
{
return boost::get<std::vector<double>>(m_data);
}
catch(...)
{
throw std::runtime_error("Trying to access a "+type()+" attribute "
"as vector");
}
}

/** Sets new value if attribute is a string. If the type is wrong
Expand Down Expand Up @@ -541,7 +574,26 @@ void IFunction::Attribute::setBool(const bool& b)
{
throw std::runtime_error("Trying to access a "+type()+" attribute "
"as bool");
}
}
}

/**
* Sets new value if attribute is a vector. If the type is wrong
* throws an exception
* @param v :: The new value
*/
void IFunction::Attribute::setVector(const std::vector<double> &v)
{
try
{
auto &value = boost::get<std::vector<double>>(m_data);
value.assign( v.begin(), v.end() );
}
catch(...)
{
throw std::runtime_error("Trying to access a "+type()+" attribute "
"as vector");
}
}

namespace
Expand Down Expand Up @@ -581,8 +633,33 @@ namespace
{
b = ( m_value == "true" || m_value == "TRUE" || m_value == "1" );
}
/// Apply if vector
void apply(std::vector<double>& v)const
{
if ( m_value.empty() )
{
v.clear();
return;
}
if ( m_value.size() > 2 )
{
// check if the value is in barckets (...)
if (m_value.front() == '(' && m_value.back() == ')')
{
m_value.erase(0,1);
m_value.erase( m_value.size()-1 );
}
}
Poco::StringTokenizer tokenizer( m_value, ",", Poco::StringTokenizer::TOK_TRIM );
v.resize( tokenizer.count() );
for (size_t i = 0; i < v.size(); ++i)
{
v[i] = boost::lexical_cast<double>( tokenizer[i] );
}

}
private:
std::string m_value; ///<the value as a string
mutable std::string m_value; ///<the value as a string
};
}

Expand Down Expand Up @@ -1011,7 +1088,20 @@ size_t IFunction::nAttributes() const
/// Check if attribute named exists
bool IFunction::hasAttribute(const std::string& name)const
{
return m_attrs.find(name) != m_attrs.end();
return m_attrs.find(name) != m_attrs.end();
}

/**
* By default it calls setAttribue for each attribute in the list.
* Implementations can override this method to make setting more eficient.
* @param attributes :: A list of attributes to set.
*/
void IFunction::setAttributes(const std::map<std::string, API::IFunction::Attribute> &attributes)
{
for(auto it = attributes.begin(); it != attributes.end(); ++it)
{
this->setAttribute( it->first, it->second );
}
}

/// Returns a list of attribute names
Expand Down

0 comments on commit 36a3244

Please sign in to comment.