From f3fe51ef652efcb731fd703a38c0d401a53755ef Mon Sep 17 00:00:00 2001 From: Kristian Bendiksen Date: Fri, 5 Mar 2021 14:04:25 +0100 Subject: [PATCH] #7116 Add extrapolation options for linear interpolation tool. --- .../Tools/RiaInterpolationTools.cpp | 27 +++++++++++- .../Application/Tools/RiaInterpolationTools.h | 13 +++++- .../UnitTests/RiaInterpolationTools-Test.cpp | 41 ++++++++++++++++++- 3 files changed, 78 insertions(+), 3 deletions(-) diff --git a/ApplicationLibCode/Application/Tools/RiaInterpolationTools.cpp b/ApplicationLibCode/Application/Tools/RiaInterpolationTools.cpp index 2ea407c714..0125f51685 100644 --- a/ApplicationLibCode/Application/Tools/RiaInterpolationTools.cpp +++ b/ApplicationLibCode/Application/Tools/RiaInterpolationTools.cpp @@ -40,7 +40,10 @@ bool almostEqual( double a, double b, double maxRelDiff = std::numeric_limits& x, const std::vector& y, double value ) +double RiaInterpolationTools::linear( const std::vector& x, + const std::vector& y, + double value, + ExtrapolationMode extrapolationMode ) { assert( x.size() == y.size() ); @@ -70,6 +73,17 @@ double RiaInterpolationTools::linear( const std::vector& x, const std::v return y[0]; else if ( almostEqual( value, x[x.size() - 1] ) ) return y[x.size() - 1]; + + if ( extrapolationMode == ExtrapolationMode::CLOSEST ) + { + return extrapolateClosestValue( x, y, value ); + } + else if ( extrapolationMode == ExtrapolationMode::TREND ) + { + return extrapolate( x, y, value ); + } + + assert( extrapolationMode == ExtrapolationMode::NONE ); return std::numeric_limits::infinity(); } @@ -94,6 +108,17 @@ double RiaInterpolationTools::extrapolate( const std::vector& x, const s return y[0] + ( value - x[0] ) / ( x[1] - x[0] ) * ( y[1] - y[0] ); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RiaInterpolationTools::extrapolateClosestValue( const std::vector& x, const std::vector& y, double value ) +{ + if ( value <= x[0] ) + return y[0]; + else + return y[x.size() - 1]; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/Application/Tools/RiaInterpolationTools.h b/ApplicationLibCode/Application/Tools/RiaInterpolationTools.h index 62ba853892..afacd4a8bf 100644 --- a/ApplicationLibCode/Application/Tools/RiaInterpolationTools.h +++ b/ApplicationLibCode/Application/Tools/RiaInterpolationTools.h @@ -26,7 +26,17 @@ class RiaInterpolationTools { public: - static double linear( const std::vector& x, const std::vector& y, double value ); + enum class ExtrapolationMode + { + NONE, + CLOSEST, + TREND + }; + + static double linear( const std::vector& x, + const std::vector& y, + double value, + ExtrapolationMode extrapolationMode = ExtrapolationMode::NONE ); // Interpolate/extrapolate away inf values in y vector. static void interpolateMissingValues( const std::vector& x, std::vector& y ); @@ -47,4 +57,5 @@ private: static int findNextDataPoint( const std::vector& values, int index ); static int findPreviousDataPoint( const std::vector& values, int index ); static double extrapolate( const std::vector& x, const std::vector& y, double value ); + static double extrapolateClosestValue( const std::vector& x, const std::vector& y, double value ); }; diff --git a/ApplicationLibCode/UnitTests/RiaInterpolationTools-Test.cpp b/ApplicationLibCode/UnitTests/RiaInterpolationTools-Test.cpp index c6058dfb38..5c37be714b 100644 --- a/ApplicationLibCode/UnitTests/RiaInterpolationTools-Test.cpp +++ b/ApplicationLibCode/UnitTests/RiaInterpolationTools-Test.cpp @@ -81,7 +81,46 @@ TEST( RiaInterpolationToolsTest, ValidIntervalValueTooHigh ) //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -TEST( RiaInterpolationToolsTest, InterpolateMisssingValuesStraightLine ) +TEST( RiaInterpolationToolsTest, ValidIntervalValueTooHighExtrapolationClosest ) +{ + std::vector x = { 0.0, 1.0 }; + std::vector y = { 0.0, 2.0 }; + + // Outside interval on high side + double res = RiaInterpolationTools::linear( x, y, 100.0, RiaInterpolationTools::ExtrapolationMode::CLOSEST ); + EXPECT_DOUBLE_EQ( 2.0, res ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST( RiaInterpolationToolsTest, ValidIntervalValueTooLowExtrapolationClosest ) +{ + std::vector x = { 0.0, 1.0 }; + std::vector y = { 0.0, 2.0 }; + + // Outside interval on low side + double res = RiaInterpolationTools::linear( x, y, -1.0, RiaInterpolationTools::ExtrapolationMode::CLOSEST ); + EXPECT_DOUBLE_EQ( 0.0, res ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST( RiaInterpolationToolsTest, ValidIntervalValueTooLowExtrapolationTrend ) +{ + std::vector x = { 0.0, 1.0 }; + std::vector y = { 0.0, 2.0 }; + + // Outside interval on low side + double res = RiaInterpolationTools::linear( x, y, -1.0, RiaInterpolationTools::ExtrapolationMode::TREND ); + EXPECT_DOUBLE_EQ( -2.0, res ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +TEST( RiaInterpolationToolsTest, InterpolateMissingValuesStraightLine ) { double inf = std::numeric_limits::infinity(); std::vector x = { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 };