Newer
Older
#include "MantidKernel/Interpolation.h"
#include "MantidKernel/Logger.h"
#include "MantidKernel/UnitFactory.h"
#include <Poco/StringTokenizer.h>
namespace Mantid
{
namespace Kernel
{
namespace
{
/// static logger
Logger g_log("Interpolation");
}
Anders Markvardsen
committed
/** Constructor default to linear interpolation and x-unit set to TOF
*/
Interpolation::Interpolation() : m_method("linear")
{
Anders Markvardsen
committed
m_xUnit = UnitFactory::Instance().create("TOF");
m_yUnit = UnitFactory::Instance().create("TOF");
}
size_t Interpolation::findIndexOfNextLargerValue(const std::vector<double> &data, double key, size_t range_start, size_t range_end) const
{
if(range_end < range_start)
{
throw std::range_error("Value is outside array range.");
}
size_t center = range_start + (range_end - range_start) / 2;
if(data[center] > key && data[center - 1] <= key) {
return center;
}
if(data[center] <= key) {
return findIndexOfNextLargerValue(data, key, center + 1, range_end);
} else {
return findIndexOfNextLargerValue(data, key, range_start, center - 1);
}
}
void Interpolation::setXUnit(const std::string& unit)
{
Anders Markvardsen
committed
m_xUnit = UnitFactory::Instance().create(unit);
}
void Interpolation::setYUnit(const std::string& unit)
{
m_yUnit = UnitFactory::Instance().create(unit);
/** Get interpolated value at location at
Janik Zikovsky
committed
* @param at :: Location where to get interpolated value
*/
Anders Markvardsen
committed
double Interpolation::value(const double& at) const
{
size_t N = m_x.size();
Anders Markvardsen
committed
{
g_log.error() << "Need at least one value for interpolation. Return interpolation value zero.";
Anders Markvardsen
committed
return 0.0;
}
if ( N == 1 )
{
return m_y[0];
}
// check first if at is within the limits of interpolation interval
{
return m_y[0]-(m_x[0]-at)*(m_y[1]-m_y[0])/(m_x[1]-m_x[0]);
}
if ( at >= m_x[N-1] )
{
return m_y[N-1]+(at-m_x[N-1])*(m_y[N-1]-m_y[N-2])/(m_x[N-1]-m_x[N-2]);
}
try {
// otherwise
// General case. Find index of next largest value by binary search.
size_t idx = findIndexOfNextLargerValue(m_x, at, 1, N - 1);
return m_y[idx-1] + (at - m_x[idx-1])*(m_y[idx]-m_y[idx-1])/(m_x[idx]-m_x[idx-1]);
} catch(std::range_error) {
return 0.0;
}
}
*
Janik Zikovsky
committed
* @param xx :: x-value
* @param yy :: y-value
*/
void Interpolation::addPoint(const double& xx, const double& yy)
{
size_t N = m_x.size();
Anders Markvardsen
committed
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
std::vector<double>::iterator it;
if ( N == 0)
{
m_x.push_back(xx); m_y.push_back(yy);
return;
}
// check first if xx is within the limits of interpolation interval
if ( xx <= m_x[0] )
{
it = m_x.begin();
it = m_x.insert ( it , xx );
it = m_y.begin();
it = m_y.insert ( it , yy );
return;
}
if ( xx >= m_x[N-1] )
{
m_x.push_back(xx); m_y.push_back(yy);
return;
}
// otherwise
for (unsigned int i = 1; i < N; i++)
{
if ( m_x[i] > xx )
{
it = m_x.begin();
it = m_x.insert ( it+i , xx );
it = m_y.begin();
it = m_y.insert ( it+i , yy );
return;
}
}
}
/**
Prints object to stream
Janik Zikovsky
committed
@param os :: the Stream to output to
Anders Markvardsen
committed
*/
void Interpolation::printSelf(std::ostream& os) const
{
os << m_method << " ; " << m_xUnit->unitID() << " ; " << m_yUnit->unitID();
Anders Markvardsen
committed
for ( unsigned int i = 0; i < m_x.size(); i++)
Anders Markvardsen
committed
{
os << " ; " << m_x[i] << " " << m_y[i];
}
}
/**
Resets interpolation data by clearing the internal storage for x- and y-values
*/
void Interpolation::resetData()
{
m_x.clear();
m_y.clear();
}
Anders Markvardsen
committed
/**
Prints the value of parameter
Janik Zikovsky
committed
@param os :: the Stream to output to
@param f :: the FitParameter to output
Anders Markvardsen
committed
@return the output stream
*/
std::ostream& operator<<(std::ostream& os, const Interpolation& f)
{
f.printSelf(os);
return os;
}
/**
Reads in parameter value
Janik Zikovsky
committed
@param in :: Input Stream
@param f :: FitParameter to write to
Anders Markvardsen
committed
@return Current state of stream
*/
std::istream& operator>>(std::istream& in, Interpolation& f)
{
typedef Poco::StringTokenizer tokenizer;
std::string str;
getline(in, str);
tokenizer values(str, ";", tokenizer::TOK_TRIM);
f.setMethod(values[0]);
f.setXUnit(values[1]);
Anders Markvardsen
committed
f.setYUnit(values[2]);
f.resetData(); // Reset data, in case the interpolation table is not empty
Anders Markvardsen
committed
for ( unsigned int i = 3; i < values.count(); i++)
Anders Markvardsen
committed
{
std::stringstream str(values[i]);
double x, y;
str >> x >> y;
f.addPoint(x,y);
}
return in;
}
} // namespace Kernel
} // namespace Mantid