Newer
Older
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidCurveFitting/BoundaryConstraint.h"
#include "MantidAPI/Expression.h"
#include "MantidAPI/ConstraintFactory.h"
Anders Markvardsen
committed
#include "MantidKernel/Logger.h"
#include <boost/lexical_cast.hpp>
#include <sstream>
namespace Mantid
{
namespace CurveFitting
{
Roman Tolchenov
committed
DECLARE_CONSTRAINT(BoundaryConstraint)
//using namespace Kernel;
using namespace API;
Anders Markvardsen
committed
// Get a reference to the logger
Kernel::Logger& BoundaryConstraint::g_log = Kernel::Logger::get("BoundaryConstraint");
/** Constructor with boundary arguments
Janik Zikovsky
committed
* @param fun :: The function
* @param paramName :: The parameter name
* @param lowerBound :: The lower bound
* @param upperBound :: The upper bound
BoundaryConstraint::BoundaryConstraint(API::IFitFunction* fun, const std::string paramName, const double lowerBound, const double upperBound) :
m_penaltyFactor(1000.0),
m_parameterName(paramName),
m_hasLowerBound( true),
m_hasUpperBound( true),
m_lowerBound(lowerBound),
m_upperBound(upperBound)
{
Russell Taylor
committed
reset(fun,fun->parameterIndex(paramName));
BoundaryConstraint::BoundaryConstraint(API::IFitFunction* fun, const std::string paramName, const double lowerBound) :
m_penaltyFactor(1000.0),
m_parameterName(paramName),
m_hasLowerBound( true),
m_hasUpperBound( false),
m_lowerBound(lowerBound)
{
reset(fun,fun->parameterIndex(paramName));
}
Roman Tolchenov
committed
/** Initialize the constraint from an expression.
Janik Zikovsky
committed
* @param fun :: The function
* @param expr :: The initializing expression which must look like this:
* " 10 < Sigma < 20 " or
* " Sigma > 20 "
Roman Tolchenov
committed
*/
void BoundaryConstraint::initialize(API::IFitFunction* fun, const API::Expression& expr)
Roman Tolchenov
committed
{
if ( expr.size() < 2 || expr.name() != "==")
Roman Tolchenov
committed
{
g_log.error("Wrong initialization expression");
throw std::invalid_argument("Wrong initialization expression");
}
clearBounds();
const Expression& terms(expr);
Roman Tolchenov
committed
std::vector<double> values(3);
int ilow = -1;
int ihi = -1;
std::string parName;
for(size_t i=0;i<terms.size();i++)
Roman Tolchenov
committed
{
Roman Tolchenov
committed
std::string name = terms[i].str();
Roman Tolchenov
committed
try
{
double d = boost::lexical_cast<double>(name);
values[i] = d;
std::string op = terms[i].operator_name();
if (op.empty())
{
op = terms[i+1].operator_name();
if (op[0] == '<')
{
Roman Tolchenov
committed
}
else if (op[0] == '>')
{
Roman Tolchenov
committed
}
else
{
g_log.error("Unknown operator in initialization expression");
throw std::invalid_argument("Unknown operator in initialization expression");
}
}// if empty
else
{
if (op[0] == '<')
{
Roman Tolchenov
committed
}
else if (op[0] == '>')
{
Roman Tolchenov
committed
}
else
{
g_log.error("Unknown operator in initialization expression");
throw std::invalid_argument("Unknown operator in initialization expression");
}
}// if not empty
}
catch(boost::bad_lexical_cast &)
Roman Tolchenov
committed
{
if ( !parName.empty() )
{
g_log.error("Non-numeric value for a bound");
throw std::invalid_argument("Non-numeric value for a bound");
}
parName = name;
}
}// for i
Roman Tolchenov
committed
size_t i = fun->parameterIndex(parName);
Roman Tolchenov
committed
reset(fun,i);
m_parameterName = parName;
}
catch(...)
{
g_log.error()<<"Parameter "<<parName<<" not found in function "<<fun->name()<<'\n';
throw;
}
Roman Tolchenov
committed
if (ilow >= 0)
{
setLower(values[ilow]);
}
if (ihi >= 0)
{
setUpper(values[ihi]);
}
}
Janik Zikovsky
committed
* @param c :: penalty factor
*/
void BoundaryConstraint::setPenaltyFactor(const double& c)
{
if (c <= 0.0)
{
g_log.warning() << "Penalty factor <= 0 selected for boundary constraint."
<< " Only positive penalty factor allowed. Penalty factor set to 1";
m_penaltyFactor = 1;
}
{
m_penaltyFactor = c;
}
}
void BoundaryConstraint::setParamToSatisfyConstraint()
{
Anders Markvardsen
committed
if ( !(m_hasLowerBound || m_hasUpperBound) )
{
g_log.warning() << "No bounds have been set on BoundaryConstraint for parameter " << m_parameterName << ". Therefore"
<< " this constraint serves no purpose!";
return;
Roman Tolchenov
committed
double paramValue = getFunction()->getParameter(getIndex());
if (m_hasLowerBound)
if ( paramValue < m_lowerBound )
Roman Tolchenov
committed
getFunction()->setParameter(getIndex(),m_lowerBound,false);
if (m_hasUpperBound)
if ( paramValue > m_upperBound )
Roman Tolchenov
committed
getFunction()->setParameter(getIndex(),m_upperBound,false);
double BoundaryConstraint::check()
Anders Markvardsen
committed
{
if ( !(m_hasLowerBound || m_hasUpperBound) )
{
g_log.warning() << "No bounds have been set on BoundaryConstraint for parameter " << m_parameterName << ". Therefore"
<< " this constraint serves no purpose!";
return 0.0;
}
Anders Markvardsen
committed
Roman Tolchenov
committed
double paramValue = getFunction()->getParameter(getIndex());
Anders Markvardsen
committed
double penalty = 0.0;
if (m_hasLowerBound)
if ( paramValue < m_lowerBound )
penalty = (m_lowerBound-paramValue)* m_penaltyFactor;
if (m_hasUpperBound)
if ( paramValue > m_upperBound )
penalty = (paramValue-m_upperBound)* m_penaltyFactor;
Anders Markvardsen
committed
return penalty;
}
double BoundaryConstraint::checkDeriv()
{
double penalty = 0.0;
Roman Tolchenov
committed
if (/*m_activeParameterIndex < 0 ||*/ !(m_hasLowerBound || m_hasUpperBound))
{
// no point in logging any warning here since checkDeriv() will always be called after
// check() is called
return penalty;
Roman Tolchenov
committed
double paramValue = getFunction()->getParameter(getIndex());
if (m_hasLowerBound)
if ( paramValue < m_lowerBound )
penalty = -m_penaltyFactor;
if (m_hasUpperBound)
if ( paramValue > m_upperBound )
penalty = m_penaltyFactor;
return penalty;
}
std::string BoundaryConstraint::asString()const
{
std::ostringstream ostr;
if (m_hasLowerBound)
{
ostr << m_lowerBound << '<';
}
Roman Tolchenov
committed
ostr << getFunction()->parameterName(getIndex());