Commit d4a58173 authored by Stephen's avatar Stephen
Browse files

Modifying Tabulated and resolution functions

Given the new changes, both functions were broken. This commit fixes them by implementing attributeName method within tabular functions and modifying how the attribute X & Y are created.
parent 1f05eaa8
......@@ -79,11 +79,16 @@ public:
double getParameter(const std::string &name) const override;
/// Check if function has a parameter with this name.
bool hasParameter(const std::string &name) const override;
/// Check if a function has an attribute with this name.
bool hasAttribute(const std::string &name) const override;
/// Return a value of attribute attName
Attribute getAttribute(const std::string &name) const override;
/// Total number of parameters
size_t nParams() const override;
// Total number of attributes
// Total number of attributes, which includes global and local function attributes
size_t nAttributes() const override;
// Total number of global attributes, defined at the composite function level
size_t nGlobalAttributes() const noexcept { return IFunction::nAttributes(); }
/// Returns the index of parameter name
size_t parameterIndex(const std::string &name) const override;
/// Returns the name of parameter i
......@@ -98,7 +103,6 @@ public:
double getError(size_t i) const override;
/// Set the fitting error for a parameter
void setError(size_t i, double err) override;
/// Value of i-th active parameter. Override this method to make fitted
/// parameters different from the declared
double activeParameter(size_t i) const override;
......@@ -211,6 +215,10 @@ protected:
/// Declare a new parameter
void declareParameter(const std::string &name, double initValue = 0,
const std::string &description = "") override;
/// Declare a single attribute
void declareAttribute(const std::string &name,
const API::IFunction::Attribute &defaultValue) override;
/// Writes itself into a string
std::string writeToString(
const std::string &parentLocalAttributesStr = "") const override;
......@@ -243,9 +251,8 @@ private:
/// Function counter to be used in nextConstraint
mutable size_t m_iConstraintFunction;
// Global attributes
void createGlobalAttributes();
void createDefaultGlobalAttributes();
std::vector<std::string> m_globalAttributeNames;
size_t m_nGlobalAttributes;
};
/// shared pointer to the composite function base class
......
......@@ -587,7 +587,7 @@ protected:
virtual void declareParameters() {}
/// Declare a single attribute
void declareAttribute(const std::string &name,
virtual void declareAttribute(const std::string &name,
const API::IFunction::Attribute &defaultValue);
/// Store an attribute's value
void storeAttributeValue(const std::string &name,
......
......@@ -27,7 +27,7 @@ namespace API {
namespace {
/// static logger
Kernel::Logger g_log("CompositeFunction");
constexpr char * ATTNUMDERIV = "NumDeriv";
constexpr char *ATTNUMDERIV = "NumDeriv";
} // namespace
using std::size_t;
......@@ -38,14 +38,13 @@ DECLARE_FUNCTION(CompositeFunction)
CompositeFunction::CompositeFunction()
: IFunction(), m_nParams(0), m_nAttributes(0),
m_iConstraintFunction(false) {
createGlobalAttributes();
createDefaultGlobalAttributes();
}
void CompositeFunction::createGlobalAttributes() {
void CompositeFunction::createDefaultGlobalAttributes() {
m_globalAttributeNames.clear();
declareAttribute(ATTNUMDERIV, Attribute(false));
m_nGlobalAttributes = 1;
m_globalAttributeNames.emplace_back(ATTNUMDERIV);
m_nAttributes = m_nGlobalAttributes;
m_nAttributes = 1;
}
/// Function initialization. Declare function parameters in this method.
......@@ -76,7 +75,7 @@ std::string CompositeFunction::writeToString(
return "name=" + name();
}
if (name() != "CompositeFunction" || nAttributes() > m_nGlobalAttributes ||
if (name() != "CompositeFunction" || nAttributes() > nGlobalAttributes() ||
getAttribute(ATTNUMDERIV).asBool() || !parentLocalAttributesStr.empty()) {
ostr << "composite=" << name();
std::vector<std::string> attr = m_globalAttributeNames;
......@@ -247,10 +246,8 @@ bool CompositeFunction::hasAttribute(const std::string &name) const {
return true;
}
auto [attributeName, index] = parseName(name);
return index < m_functions.size()
? m_functions[index]->hasAttribute(attributeName)
: false;
} catch (std::invalid_argument &) {
return m_functions[index]->hasAttribute(attributeName);
} catch (...) {
return false;
}
}
......@@ -289,11 +286,40 @@ double CompositeFunction::getParameter(const std::string &name) const {
return getFunction(index)->getParameter(parameterName);
}
/**
* Return a value of attribute attName
* @param name :: Returns the named attribute
*/
API::IFunction::Attribute
CompositeFunction::getAttribute(const std::string &name) const {
try {
if (std::find(m_globalAttributeNames.begin(), m_globalAttributeNames.end(),
name) != m_globalAttributeNames.end()) {
// Attribute is defined on the composite function, call parent method
return IFunction::getAttribute(name);
}
// Else assume that attribute is of the form fk.Attribute, so we need to
// parse the name
auto [attributeName, index] = parseName(name);
return m_functions[index]->getAttribute(attributeName);
} catch (...) {
throw std::invalid_argument(
"ParamFunctionAttributeHolder::getAttribute - Unknown attribute '" +
name + "'");
}
}
/// Total number of parameters
size_t CompositeFunction::nParams() const { return m_nParams; }
// Total number of attributes
size_t CompositeFunction::nAttributes() const { return m_nAttributes; }
size_t CompositeFunction::nAttributes() const {
size_t numAttributes = nGlobalAttributes();
for (const auto &func : m_functions) {
numAttributes += func->nAttributes();
}
return numAttributes;
}
/**
*
* @param name :: The name of a parameter
......@@ -320,13 +346,16 @@ std::string CompositeFunction::parameterName(size_t i) const {
/// @param index :: The index of the attribute
/// @return The name of the attribute
std::string CompositeFunction::attributeName(size_t index) const {
if (index < m_nGlobalAttributes)
if (index < nGlobalAttributes())
return IFunction::attributeName(index);
size_t functionIndex = attributeFunctionIndex(index - m_nGlobalAttributes);
// Offset the index by the number of global attributes
auto offsetIndex = index - nGlobalAttributes();
size_t functionIndex = attributeFunctionIndex(offsetIndex);
std::ostringstream ostr;
ostr << 'f' << functionIndex << '.'
<< m_functions[functionIndex]->attributeName(
getAttributeOffset(index - m_nGlobalAttributes));
getAttributeOffset(offsetIndex));
return ostr.str();
}
......@@ -380,8 +409,8 @@ double CompositeFunction::activeParameter(size_t i) const {
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
/// 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);
......@@ -422,7 +451,7 @@ CompositeFunction::getParameterStatus(size_t i) const {
*/
void CompositeFunction::checkFunction() {
m_nParams = 0;
m_nAttributes = m_nGlobalAttributes;
m_nAttributes = nGlobalAttributes();
m_paramOffsets.clear();
m_IFunction.clear();
m_attributeIndex.clear();
......@@ -443,6 +472,7 @@ void CompositeFunction::checkFunction() {
*/
void CompositeFunction::clear() {
m_nParams = 0;
m_nAttributes = nGlobalAttributes();
m_paramOffsets.clear();
m_IFunction.clear();
m_functions.clear();
......@@ -461,7 +491,7 @@ size_t CompositeFunction::addFunction(IFunction_sptr f) {
if (m_paramOffsets.empty()) {
m_paramOffsets.emplace_back(0);
m_nParams = f->nParams();
m_nAttributes = f->nAttributes() + m_nGlobalAttributes;
m_nAttributes = f->nAttributes() + nGlobalAttributes();
} else {
m_paramOffsets.emplace_back(m_nParams);
m_nParams += f->nParams();
......@@ -644,12 +674,12 @@ std::pair<std::string, size_t>
CompositeFunction::parseName(const std::string &varName) {
size_t i = varName.find('.');
if (i == std::string::npos) {
throw std::invalid_argument("Parameter " + varName + " not found.");
throw std::invalid_argument("Variable " + varName + " not found.");
} else {
std::string name;
if (varName[0] != 'f')
throw std::invalid_argument(
"External function parameter name must start with 'f'");
"External function variable name must start with 'f'");
std::string sindex = varName.substr(1, i - 1);
size_t index = boost::lexical_cast<size_t>(sindex);
......@@ -765,6 +795,16 @@ void CompositeFunction::declareParameter(const std::string &name,
throw Kernel::Exception::NotImplementedError(
"CompositeFunction cannot not have its own parameters.");
}
/**
* Declares a single (global) attribute on the composite function
* @param name :: The name of the attribute
* @param defaultValue :: A default value
*/
void CompositeFunction::declareAttribute(
const std::string &name, const API::IFunction::Attribute &defaultValue) {
m_globalAttributeNames.emplace_back(name);
IFunction::declareAttribute(name, defaultValue);
}
/**
* Prepare the function for a fit.
......
......@@ -48,6 +48,8 @@ public:
void setAttribute(const std::string &attName, const Attribute &) override;
/// Check if attribute attName exists
bool hasAttribute(const std::string &attName) const override;
// return attribute name from ith attribute
std::string attributeName(size_t index) const;
private:
/// Function that does the actual job
......
......@@ -77,8 +77,6 @@ public:
/// Set a value to attribute attName
void setAttribute(const std::string &attName,
const IFunction::Attribute &value) override;
/// Check if attribute attName exists
bool hasAttribute(const std::string &attName) const override;
private:
/// Call the appropriate load function
......
......@@ -55,6 +55,10 @@ bool Resolution::hasAttribute(const std::string &attName) const {
return m_fun.hasAttribute(attName);
}
std::string Resolution::attributeName(size_t index) const {
return m_fun.attributeName(index);
}
} // namespace Functions
} // namespace CurveFitting
} // namespace Mantid
......@@ -48,6 +48,8 @@ TabulatedFunction::TabulatedFunction()
declareAttribute("FileName", Attribute("", true));
declareAttribute("Workspace", Attribute(""));
declareAttribute("WorkspaceIndex", Attribute(defaultIndexValue));
declareAttribute("X", Attribute(std::vector<double>()));
declareAttribute("Y", Attribute(std::vector<double>()));
}
/// Evaluate the function for a list of arguments and given scaling factor
......@@ -56,7 +58,6 @@ void TabulatedFunction::eval(double scaling, double xshift, double xscale,
const size_t nData) const {
if (nData == 0)
return;
setupData();
if (size() == 0)
......@@ -68,13 +69,11 @@ void TabulatedFunction::eval(double scaling, double xshift, double xscale,
value *= xscale;
value += xshift;
}
const double xStart = xData.front();
const double xEnd = xData.back();
if (xStart >= xValues[nData - 1] || xEnd <= xValues[0])
return;
size_t i = 0;
while (i < nData - 1 && xValues[i] < xStart) {
out[i] = 0;
......@@ -243,15 +242,16 @@ void TabulatedFunction::setAttribute(const std::string &attName,
/// Returns the number of attributes associated with the function
size_t TabulatedFunction::nAttributes() const {
// additional X and Y attributes
return IFunction::nAttributes() + 2;
return IFunction::nAttributes();
}
/// Returns a list of attribute names
std::vector<std::string> TabulatedFunction::getAttributeNames() const {
std::vector<std::string> attNames = IFunction::getAttributeNames();
attNames.emplace_back("X");
attNames.emplace_back("Y");
//attNames.emplace_back("X");
//attNames.emplace_back("Y");
return attNames;
}
/// Return a value of attribute attName
......@@ -265,16 +265,6 @@ TabulatedFunction::getAttribute(const std::string &attName) const {
}
return IFunction::getAttribute(attName);
}
/// Check if attribute attName exists
/// @param attName :: The attribute name
bool TabulatedFunction::hasAttribute(const std::string &attName) const {
if (attName == "X" || attName == "Y") {
return true;
}
return IFunction::hasAttribute(attName);
}
/**
* Load input file as a Nexus file.
* @param fname :: The file name
......
......@@ -128,7 +128,6 @@ public:
void setHeight(const double h) override { setParameter(1, h); }
void setFwhm(const double w) override { setParameter(2, w); }
};
class ConvolutionTest_Linear : public ParamFunction, public IFunction1D {
public:
ConvolutionTest_Linear() {
......@@ -156,6 +155,35 @@ public:
}
};
class ConvolutionTest_LinearWithAttributes : public ParamFunction, public IFunction1D {
public:
ConvolutionTest_LinearWithAttributes() {
declareParameter("a");
declareParameter("b");
declareAttribute("TestAttribute", Attribute(""));
}
std::string name() const override { return "ConvolutionTest_LinearWithAttributes"; }
void function1D(double *out, const double *xValues,
const size_t nData) const override {
double a = getParameter("a");
double b = getParameter("b");
for (size_t i = 0; i < nData; i++) {
out[i] = a + b * xValues[i];
}
}
void functionDeriv1D(Jacobian *out, const double *xValues,
const size_t nData) override {
for (size_t i = 0; i < nData; i++) {
out->set(i, 0, 1.);
out->set(i, 1, xValues[i]);
}
}
};
DECLARE_FUNCTION(ConvolutionTest_Gauss)
DECLARE_FUNCTION(ConvolutionTest_Lorentz)
DECLARE_FUNCTION(ConvolutionTest_Linear)
......@@ -357,6 +385,19 @@ public:
}
}
void testAttributesSetUpCorrectlyForConvolution() {
Convolution conv;
auto func =
std::make_shared<ConvolutionTest_LinearWithAttributes>();
conv.addFunction(func);
auto names = conv.getAttributeNames();
TS_ASSERT_EQUALS(conv.nAttributes(), 3);
TS_ASSERT_EQUALS(names[0], "FixResolution");
TS_ASSERT_EQUALS(names[1], "NumDeriv");
TS_ASSERT_EQUALS(names[2], "f0.TestAttribute");
}
/*
* Convolve a Gausian (resolution) with a Delta-Dirac
*/
......
......@@ -154,6 +154,27 @@ public:
AnalysisDataService::Instance().clear();
}
void testAttributesSetUpCorrectly() {
Resolution res;
auto names = res.getAttributeNames();
TS_ASSERT_EQUALS(names.size(), 5);
TS_ASSERT_EQUALS(names[0], "FileName");
TS_ASSERT_EQUALS(names[1], "Workspace");
TS_ASSERT_EQUALS(names[2], "WorkspaceIndex");
TS_ASSERT_EQUALS(names[3], "X");
TS_ASSERT_EQUALS(names[4], "Y");
TS_ASSERT(res.hasAttribute("FileName"));
TS_ASSERT(res.hasAttribute("Workspace"));
TS_ASSERT(res.hasAttribute("WorkspaceIndex"));
TS_ASSERT(res.hasAttribute("X"));
TS_ASSERT(res.hasAttribute("Y"));
TS_ASSERT_EQUALS(res.attributeName(0), "FileName");
TS_ASSERT_EQUALS(res.attributeName(1), "Workspace");
TS_ASSERT_EQUALS(res.attributeName(2), "WorkspaceIndex");
TS_ASSERT_EQUALS(res.attributeName(3), "X");
TS_ASSERT_EQUALS(res.attributeName(4), "Y");
}
private:
const double resH, resS;
const int N;
......
......@@ -88,6 +88,7 @@ public:
TS_ASSERT(true);
TabulatedFunction fun;
fun.setAttributeValue("FileName", m_nexusFileName);
TS_ASSERT_EQUALS(fun.getParameter("Scaling"), 1.0);
TS_ASSERT_EQUALS(fun.getAttribute("FileName").asUnquotedString(),
m_nexusFileName);
......@@ -110,6 +111,7 @@ public:
TabulatedFunction fun;
fun.setAttributeValue("FileName", m_nexusFileName);
fun.setAttributeValue("WorkspaceIndex", 10);
std::cout << "fun" << fun.asString() << std::endl;
TS_ASSERT_EQUALS(fun.getParameter("Scaling"), 1.0);
TS_ASSERT_EQUALS(fun.getAttribute("FileName").asUnquotedString(),
m_nexusFileName);
......
......@@ -48,6 +48,7 @@
#include <algorithm>
#include <boost/lexical_cast.hpp>
#include <regex>
#include <utility>
namespace {
......@@ -55,6 +56,11 @@ const char *globalOptionName = "Global";
Mantid::Kernel::Logger g_log("Function Browser");
QString removePrefix(QString &param) { return param.split(QString("."))[1]; }
QString addPrefix(QString &param) { return QString("f0.") + param; }
const std::regex PREFIX_REGEX("(^[f][0-9](.*))");
inline bool variableIsPrefixed(const std::string &name) {
return std::regex_match(name, PREFIX_REGEX);
}
} // namespace
namespace MantidQt {
......@@ -482,13 +488,13 @@ protected:
/// Create string property
FunctionTreeView::AProperty apply(const std::string &str) const override {
QtProperty *prop = nullptr;
if (m_attName == "FileName") {
if (m_attName.indexOf("FileName") != -1) {
prop = m_browser->m_filenameManager->addProperty(m_attName);
m_browser->m_filenameManager->setValue(prop, QString::fromStdString(str));
} else if (m_attName == "Formula") {
} else if (m_attName.indexOf("Formula") != -1) {
prop = m_browser->m_formulaManager->addProperty(m_attName);
m_browser->m_formulaManager->setValue(prop, QString::fromStdString(str));
} else if (m_attName == "Workspace") {
} else if (m_attName.indexOf("Workspace") != -1) {
prop = m_browser->m_workspaceManager->addProperty(m_attName);
m_browser->m_workspaceManager->setValue(prop,
QString::fromStdString(str));
......@@ -644,9 +650,11 @@ void FunctionTreeView::addAttributeAndParameterProperties(
// add attribute properties
auto attributeNames = fun->getAttributeNames();
for (auto att = attributeNames.begin(); att != attributeNames.end(); ++att) {
QString attName = QString::fromStdString(*att);
addAttributeProperty(prop, attName, fun->getAttribute(*att));
for (const auto &att : attributeNames) {
if (!variableIsPrefixed(att)) {
QString attName = QString::fromStdString(att);
addAttributeProperty(prop, attName, fun->getAttribute(att));
}
}
auto cf = std::dynamic_pointer_cast<Mantid::API::CompositeFunction>(fun);
......
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