Skip to content

Commit

Permalink
Re #9682. Expanded unit tests for Interpolation
Browse files Browse the repository at this point in the history
The edge-cases of an interpolation are now clearly separated and checked in a uniform way.
  • Loading branch information
Michael Wedel committed Jun 23, 2014
1 parent a451716 commit 1804557
Showing 1 changed file with 126 additions and 32 deletions.
158 changes: 126 additions & 32 deletions Code/Mantid/Framework/Kernel/test/InterpolationTest.h
Expand Up @@ -10,6 +10,47 @@ using namespace Mantid::Kernel;
class InterpolationTest : public CxxTest::TestSuite
{
public:
/* In the constructor some vectors with values are setup,
* which make the tests easier later on.
*
* To check the interpolated values, call the method
* checkInterpolationResults(const Interpolation &interpolation);
* and supply the interpolation object which is to be tested. The method will call
* further methods to cover all possible edge-cases. On failure, it will be visible
* which case caused the failure.
*/
InterpolationTest()
{
// values for setting up the interpolation
m_tableXValues.push_back(200.0);
m_tableXValues.push_back(201.0);
m_tableXValues.push_back(202.0);
m_tableXValues.push_back(203.0);
m_tableXValues.push_back(204.0);

m_tableYValues.push_back(50);
m_tableYValues.push_back(60);
m_tableYValues.push_back(100);
m_tableYValues.push_back(300);
m_tableYValues.push_back(400);

// bulk values for interpolation test
m_interpolationXValues.push_back(200.5);
m_interpolationXValues.push_back(201.25);
m_interpolationXValues.push_back(203.5);

m_expectedYValues.push_back(55.0);
m_expectedYValues.push_back(70.0);
m_expectedYValues.push_back(350.0);

// values outside interpolation range
m_outsideXValues.push_back(100.0);
m_outsideXValues.push_back(3000.0);

m_outsideYValues.push_back(-950.0);
m_outsideYValues.push_back(280000.0);
}

void testCopyConstruction()
{
Interpolation interpolation;
Expand Down Expand Up @@ -47,25 +88,29 @@ class InterpolationTest : public CxxTest::TestSuite
TS_ASSERT(interpolation.containData() == false);
}

void testAddPoint()
void testAddPointOrdered()
{
Interpolation interpolation;

// insertion order does not matter, interpolation table is always sorted internally
interpolation.addPoint(200.0, 50);
interpolation.addPoint(201.0, 60);
interpolation.addPoint(202.0, 100);
interpolation.addPoint(204.0, 400);
interpolation.addPoint(203.0, 300);
// Add points from values in vectors in correct order.
for(size_t i = 0; i < m_tableXValues.size(); ++i) {
interpolation.addPoint(m_tableXValues[i], m_tableYValues[i]);
}

// Check correctness of interpolation for different cases
checkInterpolationResults(interpolation);
}

void testAddPointArbitrary()
{
Interpolation interpolation;

// Test that all the base class member variables are correctly assigned to
TS_ASSERT_DELTA( interpolation.value(100), -950.0 ,0.000000001);
TS_ASSERT_DELTA( interpolation.value(3000), 280000.0 ,0.000000001);
TS_ASSERT_DELTA( interpolation.value(200.5), 55.0 ,0.000000001);
TS_ASSERT_DELTA( interpolation.value(201.25), 70.0 ,0.000000001);
TS_ASSERT_DELTA( interpolation.value(203.5), 350.0 ,0.000000001);
std::vector<size_t> insertionOrder = {1, 0, 3, 4, 2};
for(std::vector<size_t>::const_iterator i = insertionOrder.begin(); i != insertionOrder.end(); ++i) {
interpolation.addPoint(m_tableXValues[*i], m_tableYValues[*i]);
}

TS_ASSERT_EQUALS(interpolation.value(204.0), 400.0);
checkInterpolationResults(interpolation);
}

void testEmpty()
Expand Down Expand Up @@ -102,12 +147,7 @@ class InterpolationTest : public CxxTest::TestSuite
TS_ASSERT( readIn.getXUnit()->unitID() == xUnit );
TS_ASSERT( readIn.getYUnit()->unitID() == yUnit );

// Test that all the base class member variables are correctly assigned to
TS_ASSERT_DELTA( readIn.value(100), -950.0 ,0.000000001);
TS_ASSERT_DELTA( readIn.value(3000), 280000.0 ,0.000000001);
TS_ASSERT_DELTA( readIn.value(200.5), 55.0 ,0.000000001);
TS_ASSERT_DELTA( readIn.value(201.25), 70.0 ,0.000000001);
TS_ASSERT_DELTA( readIn.value(203.5), 350.0 ,0.000000001);
checkInterpolationResults(readIn);
}

void testStreamOperatorsNonEmpty()
Expand All @@ -120,32 +160,86 @@ class InterpolationTest : public CxxTest::TestSuite
// Reconstruct on existing object.
str >> interpolation;

TS_ASSERT_DELTA( interpolation.value(100), -950.0 ,0.000000001);
TS_ASSERT_DELTA( interpolation.value(3000), 280000.0 ,0.000000001);
TS_ASSERT_DELTA( interpolation.value(200.5), 55.0 ,0.000000001);
TS_ASSERT_DELTA( interpolation.value(201.25), 70.0 ,0.000000001);
TS_ASSERT_DELTA( interpolation.value(203.5), 350.0 ,0.000000001);

TS_ASSERT_EQUALS( interpolation.value(201.0), 60.0)
checkInterpolationResults(interpolation);
}

private:
Interpolation getInitializedInterpolation(std::string xUnit, std::string yUnit)
{
Interpolation interpolation;

interpolation.addPoint(200.0, 50);
interpolation.addPoint(201.0, 60);
interpolation.addPoint(202.0, 100);
interpolation.addPoint(203.0, 300);
interpolation.addPoint(204.0, 400);
// take values from constructor
for(size_t i = 0; i < m_tableXValues.size(); ++i) {
interpolation.addPoint(m_tableXValues[i], m_tableYValues[i]);
}

interpolation.setXUnit(xUnit);
interpolation.setYUnit(yUnit);

return interpolation;
}

void checkInterpolationResults(const Interpolation &interpolation)
{
checkValueAtLowerLimit(interpolation);
checkValueAtUpperLimit(interpolation);
checkValuesAtExactBulkPoints(interpolation);
checkValuesInsideInterpolationRange(interpolation);
checkValuesOutsideInterpolationRange(interpolation);
}

void checkValueAtLowerLimit(const Interpolation &interpolation)
{
checkValue(interpolation, m_tableXValues.front(), m_tableYValues.front(), "at lower limit");
}

void checkValueAtUpperLimit(const Interpolation &interpolation)
{
checkValue(interpolation, m_tableXValues.back(), m_tableYValues.back(), "at upper limit");
}

void checkValuesAtExactBulkPoints(const Interpolation &interpolation)
{
for(size_t i = 1; i < m_tableXValues.size() - 1; ++i) {
checkValue(interpolation, m_tableXValues[i], m_tableYValues[i], "at interpolation point");
}
}

void checkValuesInsideInterpolationRange(const Interpolation &interpolation) {
for(size_t i = 0; i < m_interpolationXValues.size(); ++i) {
checkValue(interpolation, m_interpolationXValues[i], m_expectedYValues[i], "inside interpolation range");
}
}

void checkValuesOutsideInterpolationRange(const Interpolation &interpolation)
{
for(size_t i = 0; i < m_outsideXValues.size(); ++i) {
checkValue(interpolation, m_outsideXValues[i], m_outsideYValues[i], "outside interpolation range");
}
}

/* This function performs the actual check.
* It takes a string argument to make it more obvious where the problem is.
*/
void checkValue(const Interpolation &interpolation, double x, double y, std::string testedRange)
{
std::ostringstream errorString;
errorString << "Interpolation error " << testedRange;

TSM_ASSERT_EQUALS(errorString.str().c_str(), interpolation.value(x), y);
}

// These two vectors contain the data points from which the interpolation is constructed
std::vector<double> m_tableXValues;
std::vector<double> m_tableYValues;

// Two vectors with test values for the "bulk", e.g. no values at the limits and
std::vector<double> m_interpolationXValues;
std::vector<double> m_expectedYValues;

// Values outside interpolation range
std::vector<double> m_outsideXValues;
std::vector<double> m_outsideYValues;
};

#endif /*INTERPOLATIONTEST_H_*/

0 comments on commit 1804557

Please sign in to comment.