Commit ccd49545 authored by Roman Tolchenov's avatar Roman Tolchenov
Browse files

Re #9439. Added code to parse index ranges in 'domains' attributes

parent 0d9da94e
......@@ -72,7 +72,9 @@ public:
/// Get domain indices for a member function
void getDomainIndices(size_t i, size_t nDomains, std::vector<size_t>& domains)const;
/// Returns the number of attributes associated with the function
/// Returns the number of "local" attributes associated with the function.
/// Local attributes are attributes of MultiDomainFunction but describe properties
/// of individual member functions.
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");}
......
......@@ -232,7 +232,24 @@ namespace API
}
/**
* Set a value to attribute attName
* Set a value to a "local" attribute, ie an attribute related to a member function.
*
* The only attribute that can be set here is "domains" which defines the
* indices of domains a particular function is applied to. Possible values are (strings):
*
* 1) "All" : the function is applied to all domains defined for this MultiDomainFunction.
* 2) "i" : the function is applied to a single domain which index is equal to the
* function's index in this MultiDomainFunction.
* 3) "non-negative integer" : a domain index.
* 4) "a,b,c,..." : a list of domain indices (a,b,c,.. are non-negative integers).
* 5) "a - b" : a range of domain indices (a,b are non-negative integers a <= b).
*
* To be used with Fit algorithm at least one of the member functions must have "domains" value
* of type 2), 3), 4) or 5) because these values can tell Fit how many domains need to be created.
*
* @param i :: Index of a function for which the attribute is being set.
* @param attName :: Name of an attribute.
* @param att :: Value of the attribute to set.
*/
void MultiDomainFunction::setLocalAttribute(size_t i, const std::string& attName,const IFunction::Attribute& att)
{
......@@ -263,15 +280,40 @@ namespace API
else if (value.empty())
{// do not fit to any domain
setDomainIndices(i,std::vector<size_t>());
return;
}
// 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)
if (list.name() == "+")
{
if ( list.size() != 2 || list.terms()[1].operator_name() != "-" )
{
throw std::runtime_error("MultiDomainFunction: attribute \"domains\" expects two integers separated by a \"-\"");
}
// value looks like "a - b". a and b must be ints and define a range of domain indices
size_t start = boost::lexical_cast<size_t>( list.terms()[0].str() );
size_t end = boost::lexical_cast<size_t>( list.terms()[1].str() ) + 1;
if ( start >= end )
{
throw std::runtime_error("MultiDomainFunction: attribute \"domains\": wrong range limits.");
}
indx.resize( end - start );
for(size_t i = start; i < end; ++i)
{
indx[i - start] = i;
}
}
else
{
indx.push_back(boost::lexical_cast<size_t>(list[k].name()));
// value must be either an int or a list of ints: "a,b,c,..."
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);
}
......
......@@ -299,6 +299,43 @@ public:
}
void test_attribute_domain_range()
{
multi.clearDomainIndices();
multi.setLocalAttributeValue(0,"domains","0-2");
return;
multi.setLocalAttributeValue(1,"domains","i");
multi.setLocalAttributeValue(2,"domains","i");
FunctionValues values(domain);
multi.function(domain,values);
double A = multi.getFunction(0)->getParameter("A");
double B = multi.getFunction(0)->getParameter("B");
const FunctionDomain1D& d0 = static_cast<const FunctionDomain1D&>(domain.getDomain(0));
for(size_t i = 0; i < 9; ++i)
{
TS_ASSERT_EQUALS(values.getCalculated(i), A + B * d0[i]);
}
A = multi.getFunction(0)->getParameter("A") + multi.getFunction(1)->getParameter("A");
B = multi.getFunction(0)->getParameter("B") + multi.getFunction(1)->getParameter("B");
const FunctionDomain1D& d1 = static_cast<const FunctionDomain1D&>(domain.getDomain(1));
for(size_t i = 9; i < 19; ++i)
{
TS_ASSERT_EQUALS(values.getCalculated(i), A + B * d1[i-9]);
}
A = multi.getFunction(0)->getParameter("A") + multi.getFunction(2)->getParameter("A");
B = multi.getFunction(0)->getParameter("B") + multi.getFunction(2)->getParameter("B");
const FunctionDomain1D& d2 = static_cast<const FunctionDomain1D&>(domain.getDomain(2));
for(size_t i = 19; i < 30; ++i)
{
TS_ASSERT_EQUALS(values.getCalculated(i), A + B * d2[i-19]);
}
}
void test_attribute_in_FunctionFactory()
{
std::string ini = "composite=MultiDomainFunction;"
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment