-
Federico Montesino Pouzols authoredFederico Montesino Pouzols authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ParamFunction.cpp 14.83 KiB
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidKernel/Exception.h"
#include "MantidKernel/Logger.h"
#include "MantidAPI/ParamFunction.h"
#include "MantidAPI/IConstraint.h"
#include "MantidAPI/ParameterTie.h"
#include <boost/lexical_cast.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
#include <sstream>
#include <limits>
namespace Mantid {
namespace API {
namespace {
Kernel::Logger g_log("ParamFunction");
}
/// Destructor
ParamFunction::~ParamFunction() {
for (std::vector<ParameterTie *>::iterator it = m_ties.begin();
it != m_ties.end(); ++it) {
delete *it;
}
m_ties.clear();
for (std::vector<IConstraint *>::iterator it = m_constraints.begin();
it != m_constraints.end(); ++it) {
delete *it;
}
m_constraints.clear();
}
/** Sets a new value to the i-th parameter.
* @param i :: The parameter index
* @param value :: The new value
* @param explicitlySet :: A boolean falgging the parameter as explicitly set
* (by user)
*/
void ParamFunction::setParameter(size_t i, const double &value,
bool explicitlySet) {
// Cppcheck confused by the check for NaN
if (boost::math::isnan(value)) {
// Check for NaN or -NaN
std::stringstream errmsg;
errmsg << "Trying to set a NaN or infinity value (" << value
<< ") to parameter " << this->parameterName(i);
g_log.warning(errmsg.str());
// throw std::runtime_error(errmsg.str());
} else if (value <= -DBL_MAX || value >= DBL_MAX) {
// Infinity value
std::stringstream errmsg;
errmsg << "Trying to set an infinity value (" << value << ") to parameter "
<< this->parameterName(i);
g_log.warning(errmsg.str());
// throw std::runtime_error(errmsg.str());
}
if (i >= nParams()) {
throw std::out_of_range("ParamFunction parameter index out of range.");
}
if (explicitlySet && value != m_parameters[i]) {
m_explicitlySet[i] = true;
}
m_parameters[i] = value;
}
/** Sets a new parameter description to the i-th parameter.
* @param i :: The parameter index
* @param description :: New parameter description
*/
void ParamFunction::setParameterDescription(size_t i,
const std::string &description) {
if (i >= nParams()) {
throw std::out_of_range("ParamFunction parameter index out of range.");
}
m_parameterDescriptions[i] = description;
}
/** Get the i-th parameter.
* @param i :: The parameter index
* @return the value of the requested parameter
*/
double ParamFunction::getParameter(size_t i) const {
if (i >= nParams()) {
throw std::out_of_range("ParamFunction parameter index out of range.");
}
return m_parameters[i];
}
/**
* Sets a new value to a parameter by name.
* @param name :: The name of the parameter.
* @param value :: The new value
* @param explicitlySet :: A boolean flagging the parameter as explicitly set
* (by user)
*/
void ParamFunction::setParameter(const std::string &name, const double &value,
bool explicitlySet) {
std::string ucName(name);
// std::transform(name.begin(), name.end(), ucName.begin(), toupper);
std::vector<std::string>::const_iterator it =
std::find(m_parameterNames.begin(), m_parameterNames.end(), ucName);
if (it == m_parameterNames.end()) {
std::ostringstream msg;
msg << "ParamFunction tries to set value to non-exist parameter (" << ucName
<< ") "
<< "of function " << this->name();
msg << "\nAllowed parameters: ";
for (size_t ist = 0; ist < m_parameterNames.size(); ++ist) {
msg << m_parameterNames[ist] << ", ";
}
throw std::invalid_argument(msg.str());
}
setParameter(static_cast<int>(it - m_parameterNames.begin()), value,
explicitlySet);
}
/**
* Sets a new description to a parameter by name.
* @param name :: The name of the parameter.
* @param description :: New parameter description
*/
void ParamFunction::setParameterDescription(const std::string &name,
const std::string &description) {
std::string ucName(name);
// std::transform(name.begin(), name.end(), ucName.begin(), toupper);
std::vector<std::string>::const_iterator it =
std::find(m_parameterNames.begin(), m_parameterNames.end(), ucName);
if (it == m_parameterNames.end()) {
std::ostringstream msg;
msg << "ParamFunction tries to set description to non-exist parameter ("
<< ucName << "). ";
msg << "\nAllowed parameters: ";
for (size_t ist = 0; ist < m_parameterNames.size(); ++ist)
msg << m_parameterNames[ist] << ", ";
throw std::invalid_argument(msg.str());
}
setParameterDescription(static_cast<int>(it - m_parameterNames.begin()),
description);
}
/**
* Parameters by name.
* @param name :: The name of the parameter.
* @return the value of the named parameter
*/
double ParamFunction::getParameter(const std::string &name) const {
std::string ucName(name);
// std::transform(name.begin(), name.end(), ucName.begin(), toupper);
std::vector<std::string>::const_iterator it =
std::find(m_parameterNames.begin(), m_parameterNames.end(), ucName);
if (it == m_parameterNames.end()) {
std::ostringstream msg;
msg << "ParamFunction tries to get value of non-existing parameter ("
<< ucName << ") "
<< "to function " << this->name();
msg << "\nAllowed parameters: ";
for (size_t ist = 0; ist < m_parameterNames.size(); ++ist)
msg << m_parameterNames[ist] << ", ";
throw std::invalid_argument(msg.str());
}
double parvalue = m_parameters[it - m_parameterNames.begin()];
if (parvalue != parvalue || !(parvalue > -DBL_MAX && parvalue < DBL_MAX)) {
g_log.warning() << "Parameter " << name << " has a NaN or infinity value "
<< std::endl;
}
return parvalue;
}
/**
* Returns the index of the parameter named name.
* @param name :: The name of the parameter.
* @return the index of the named parameter
*/
size_t ParamFunction::parameterIndex(const std::string &name) const {
std::string ucName(name);
// std::transform(name.begin(), name.end(), ucName.begin(), toupper);
std::vector<std::string>::const_iterator it =
std::find(m_parameterNames.begin(), m_parameterNames.end(), ucName);
if (it == m_parameterNames.end()) {
std::ostringstream msg;
msg << "ParamFunction " << this->name() << " does not have parameter ("
<< ucName << ").";
throw std::invalid_argument(msg.str());
}
return int(it - m_parameterNames.begin());
}
/** Returns the name of parameter i
* @param i :: The index of a parameter
* @return the name of the parameter at the requested index
*/
std::string ParamFunction::parameterName(size_t i) const {
if (i >= nParams()) {
throw std::out_of_range("ParamFunction parameter index out of range.");
}
return m_parameterNames[i];
}
/** Returns the description of parameter i
* @param i :: The index of a parameter
* @return the description of the parameter at the requested index
*/
std::string ParamFunction::parameterDescription(size_t i) const {
if (i >= nParams()) {
throw std::out_of_range("ParamFunction parameter index out of range.");
}
return m_parameterDescriptions[i];
}
/**
* Get the fitting error for a parameter
* @param i :: The index of a parameter
* @return :: the error
*/
double ParamFunction::getError(size_t i) const {
if (i >= nParams()) {
throw std::out_of_range("ParamFunction parameter index out of range.");
}
return m_errors[i];
}
/**
* Set the fitting error for a parameter
* @param i :: The index of a parameter
* @param err :: The error value to set
*/
void ParamFunction::setError(size_t i, double err) {
if (i >= nParams()) {
throw std::out_of_range("ParamFunction parameter index out of range.");
}
m_errors[i] = err;
}
/**
* Declare a new parameter. To used in the implementation'c constructor.
* @param name :: The parameter name.
* @param initValue :: The initial value for the parameter
* @param description :: The description for the parameter
*/
void ParamFunction::declareParameter(const std::string &name, double initValue,
const std::string &description) {
std::string ucName(name);
// std::transform(name.begin(), name.end(), ucName.begin(), toupper);
std::vector<std::string>::const_iterator it =
std::find(m_parameterNames.begin(), m_parameterNames.end(), ucName);
if (it != m_parameterNames.end()) {
std::ostringstream msg;
msg << "ParamFunction parameter (" << ucName << ") already exists.";
throw std::invalid_argument(msg.str());
}
m_isFixed.push_back(false);
m_parameterNames.push_back(ucName);
m_parameterDescriptions.push_back(description);
m_parameters.push_back(initValue);
m_errors.push_back(0.0);
m_explicitlySet.push_back(false);
}
/**
* query if the parameter is fixed
* @param i :: The index of a declared parameter
* @return true if parameter i is active
*/
bool ParamFunction::isFixed(size_t i) const {
if (i >= nParams())
throw std::out_of_range("ParamFunction parameter index out of range.");
return m_isFixed[i];
}
/** This method doesn't create a tie
* @param i :: A declared parameter index to be fixed
*/
void ParamFunction::fix(size_t i) {
if (isFixed(i))
return;
m_isFixed[i] = true;
}
/** Makes a parameter active again. It doesn't change the parameter's tie.
* @param i :: A declared parameter index to be restored to active
*/
void ParamFunction::unfix(size_t i) {
if (!isFixed(i))
return;
m_isFixed[i] = false;
}
/**
* Attaches a tie to this ParamFunction. The attached tie is owned by the
* ParamFunction.
* @param tie :: A pointer to a new tie
*/
void ParamFunction::addTie(ParameterTie *tie) {
size_t iPar = tie->getIndex();
bool found = false;
for (std::vector<ParameterTie *>::size_type i = 0; i < m_ties.size(); i++) {
if (m_ties[i]->getIndex() == iPar) {
found = true;
delete m_ties[i];
m_ties[i] = tie;
break;
}
}
if (!found) {
m_ties.push_back(tie);
}
}
/**
* Apply the ties.
*/
void ParamFunction::applyTies() {
for (std::vector<ParameterTie *>::iterator tie = m_ties.begin();
tie != m_ties.end(); ++tie) {
(**tie).eval();
}
}
/**
* Used to find ParameterTie for a parameter i
*/
class ReferenceEqual {
const size_t m_i; ///< index to find
public:
/** Constructor
*/
ReferenceEqual(size_t i) : m_i(i) {}
/**Bracket operator
* @param p :: the parameter you are looking for
* @return True if found
*/
bool operator()(ParameterReference *p) { return p->getIndex() == m_i; }
};
/** Removes i-th parameter's tie if it is tied or does nothing.
* @param i :: The index of the tied parameter.
* @return True if successfull
*/
bool ParamFunction::removeTie(size_t i) {
if (i >= nParams()) {
throw std::out_of_range("ParamFunction parameter index out of range.");
}
std::vector<ParameterTie *>::iterator it =
std::find_if(m_ties.begin(), m_ties.end(), ReferenceEqual(i));
if (it != m_ties.end()) {
delete *it;
m_ties.erase(it);
unfix(i);
return true;
}
return false;
}
/** Get tie of parameter number i
* @param i :: The index of a declared parameter.
* @return A pointer to the tie
*/
ParameterTie *ParamFunction::getTie(size_t i) const {
if (i >= nParams()) {
throw std::out_of_range("ParamFunction parameter index out of range.");
}
std::vector<ParameterTie *>::const_iterator it =
std::find_if(m_ties.begin(), m_ties.end(), ReferenceEqual(i));
if (it != m_ties.end()) {
return *it;
}
return NULL;
}
/** Remove all ties
*/
void ParamFunction::clearTies() {
for (std::vector<ParameterTie *>::iterator it = m_ties.begin();
it != m_ties.end(); ++it) {
size_t i = getParameterIndex(**it);
unfix(i);
delete *it;
}
m_ties.clear();
}
/** Add a constraint
* @param ic :: Pointer to a constraint.
*/
void ParamFunction::addConstraint(IConstraint *ic) {
size_t iPar = ic->getIndex();
bool found = false;
for (std::vector<IConstraint *>::size_type i = 0; i < m_constraints.size();
i++) {
if (m_constraints[i]->getIndex() == iPar) {
found = true;
delete m_constraints[i];
m_constraints[i] = ic;
break;
}
}
if (!found) {
m_constraints.push_back(ic);
}
}
/** Get constraint of parameter number i
* @param i :: The index of a declared parameter.
* @return A pointer to the constraint or NULL
*/
IConstraint *ParamFunction::getConstraint(size_t i) const {
if (i >= nParams()) {
throw std::out_of_range("ParamFunction parameter index out of range.");
}
std::vector<IConstraint *>::const_iterator it = std::find_if(
m_constraints.begin(), m_constraints.end(), ReferenceEqual(i));
if (it != m_constraints.end()) {
return *it;
}
return NULL;
}
/** Remove a constraint
* @param parName :: The name of a parameter which constarint to remove.
*/
void ParamFunction::removeConstraint(const std::string &parName) {
size_t iPar = parameterIndex(parName);
for (std::vector<IConstraint *>::iterator it = m_constraints.begin();
it != m_constraints.end(); ++it) {
if (iPar == (**it).getIndex()) {
delete *it;
m_constraints.erase(it);
break;
}
}
}
void ParamFunction::setUpForFit() {
for (size_t i = 0; i < m_constraints.size(); i++) {
m_constraints[i]->setParamToSatisfyConstraint();
}
}
/// Nonvirtual member which removes all declared parameters
void ParamFunction::clearAllParameters() {
for (std::vector<ParameterTie *>::iterator it = m_ties.begin();
it != m_ties.end(); ++it) {
delete *it;
}
m_ties.clear();
for (std::vector<IConstraint *>::iterator it = m_constraints.begin();
it != m_constraints.end(); ++it) {
delete *it;
}
m_constraints.clear();
m_parameters.clear();
m_parameterNames.clear();
m_parameterDescriptions.clear();
m_isFixed.clear();
}
/// Get the address of the parameter
/// @param i :: the index of the parameter required
/// @returns the address of the parameter
double *ParamFunction::getParameterAddress(size_t i) {
if (i >= nParams()) {
throw std::out_of_range("ParamFunction parameter index out of range.");
}
return &m_parameters[i];
}
/// Checks if a parameter has been set explicitly
bool ParamFunction::isExplicitlySet(size_t i) const {
if (i >= nParams()) {
throw std::out_of_range("ParamFunction parameter index out of range.");
}
return m_explicitlySet[i];
}
/**
* Returns the index of parameter if the ref points to this ParamFunction
* @param ref :: A reference to a parameter
* @return Parameter index or number of nParams() if parameter not found
*/
size_t ParamFunction::getParameterIndex(const ParameterReference &ref) const {
if (ref.getFunction() == this && ref.getIndex() < nParams()) {
return ref.getIndex();
}
return nParams();
}
} // namespace API
} // namespace Mantid