mirror of
https://github.com/OPM/ResInsight.git
synced 2024-12-28 01:41:42 -06:00
#11954 Improve the curve merger algorithm
* Add flag to indicate identical X values when curves are merged * Detect if x values are monotonically increasing
This commit is contained in:
parent
d90dd91e29
commit
1ce2f9651c
@ -67,7 +67,8 @@ public:
|
||||
interpolatedYValue( const XValueType& xValue, const std::vector<XValueType>& curveXValues, const std::vector<double>& curveYValues );
|
||||
|
||||
private:
|
||||
void computeUnionOfXValues( bool includeValuesFromPartialCurves );
|
||||
void computeUnionOfXValues( bool includeValuesFromPartialCurves );
|
||||
static bool isMonotonicallyIncreasing( const std::vector<XValueType>& curveXValues );
|
||||
|
||||
private:
|
||||
std::vector<std::pair<std::vector<XValueType>, std::vector<double>>> m_originalValues;
|
||||
@ -76,6 +77,9 @@ private:
|
||||
|
||||
std::vector<XValueType> m_allXValues;
|
||||
std::vector<std::vector<double>> m_interpolatedValuesForAllCurves;
|
||||
|
||||
bool m_isXValuesSharedBetweenCurves;
|
||||
bool m_isXValuesMonotonicallyIncreasing;
|
||||
};
|
||||
|
||||
using RiaTimeHistoryCurveMerger = RiaCurveMerger<time_t>;
|
||||
|
@ -55,6 +55,8 @@ bool XValueComparator<XValueType>::equals( const XValueType& lhs, const XValueTy
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename XValueType>
|
||||
RiaCurveMerger<XValueType>::RiaCurveMerger()
|
||||
: m_isXValuesSharedBetweenCurves( false )
|
||||
, m_isXValuesMonotonicallyIncreasing( true )
|
||||
{
|
||||
}
|
||||
|
||||
@ -68,6 +70,24 @@ void RiaCurveMerger<XValueType>::addCurveData( const std::vector<XValueType>& xV
|
||||
|
||||
if ( !xValues.empty() )
|
||||
{
|
||||
if ( m_originalValues.empty() )
|
||||
{
|
||||
m_isXValuesSharedBetweenCurves = true;
|
||||
m_isXValuesMonotonicallyIncreasing = isMonotonicallyIncreasing( xValues );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_isXValuesSharedBetweenCurves )
|
||||
{
|
||||
const auto& firstXValues = m_originalValues.front().first;
|
||||
m_isXValuesSharedBetweenCurves = std::equal( firstXValues.begin(), firstXValues.end(), xValues.begin() );
|
||||
}
|
||||
|
||||
if ( m_isXValuesMonotonicallyIncreasing )
|
||||
{
|
||||
m_isXValuesMonotonicallyIncreasing = isMonotonicallyIncreasing( xValues );
|
||||
}
|
||||
}
|
||||
m_originalValues.push_back( std::make_pair( xValues, yValues ) );
|
||||
}
|
||||
}
|
||||
@ -131,14 +151,14 @@ void RiaCurveMerger<XValueType>::computeInterpolatedValues( bool includeValuesFr
|
||||
m_allXValues.clear();
|
||||
m_interpolatedValuesForAllCurves.clear();
|
||||
|
||||
computeUnionOfXValues( includeValuesFromPartialCurves );
|
||||
|
||||
const size_t curveCount = m_originalValues.size();
|
||||
if ( curveCount == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
computeUnionOfXValues( includeValuesFromPartialCurves );
|
||||
|
||||
const size_t dataValueCount = m_allXValues.size();
|
||||
if ( dataValueCount == 0 )
|
||||
{
|
||||
@ -157,8 +177,18 @@ void RiaCurveMerger<XValueType>::computeInterpolatedValues( bool includeValuesFr
|
||||
#pragma omp parallel for
|
||||
for ( int valueIndex = 0; valueIndex < static_cast<int>( dataValueCount ); valueIndex++ )
|
||||
{
|
||||
double interpolValue =
|
||||
interpolatedYValue( m_allXValues[valueIndex], m_originalValues[curveIdx].first, m_originalValues[curveIdx].second );
|
||||
double interpolValue = 0.0;
|
||||
|
||||
if ( m_isXValuesSharedBetweenCurves )
|
||||
{
|
||||
interpolValue = m_originalValues[curveIdx].second[valueIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
interpolValue =
|
||||
interpolatedYValue( m_allXValues[valueIndex], m_originalValues[curveIdx].first, m_originalValues[curveIdx].second );
|
||||
}
|
||||
|
||||
if ( !RiaCurveDataTools::isValidValue( interpolValue, false ) )
|
||||
{
|
||||
#pragma omp critical
|
||||
@ -180,6 +210,13 @@ void RiaCurveMerger<XValueType>::computeUnionOfXValues( bool includeValuesForPar
|
||||
{
|
||||
m_allXValues.clear();
|
||||
|
||||
if ( m_isXValuesSharedBetweenCurves && !m_originalValues.empty() )
|
||||
{
|
||||
// If all curves have the same X values, use the X values from the first curve.
|
||||
m_allXValues = m_originalValues.front().first;
|
||||
return;
|
||||
}
|
||||
|
||||
std::set<XValueType, XComparator> unionOfXValues;
|
||||
|
||||
std::vector<std::pair<XValueType, XValueType>> originalXBounds;
|
||||
@ -240,17 +277,27 @@ double RiaCurveMerger<XValueType>::interpolatedYValue( const XValueType&
|
||||
if ( xValues.empty() ) return HUGE_VAL;
|
||||
if ( yValues.size() != xValues.size() ) return HUGE_VAL;
|
||||
|
||||
size_t startIndex = 0;
|
||||
|
||||
if ( isMonotonicallyIncreasing( xValues ) )
|
||||
{
|
||||
// Use lower_bound to find the first element that is not less than the interpolation value using a threshold that is larger than
|
||||
// the threshold used in XComparator::equals
|
||||
//
|
||||
// Using this method will improve the performance significantly for large datasets, as std::lower_bound is much faster than the
|
||||
// search in the loop below. One relevant use case is computation of delta summary values for large datasets. Here the time
|
||||
// steps are specified in increasing order
|
||||
//
|
||||
XValueType threshold = 1.0e-6 * xValues.back();
|
||||
auto it = std::lower_bound( xValues.begin(), xValues.end(), interpolationXValue - threshold );
|
||||
if ( it == xValues.end() ) return HUGE_VAL;
|
||||
|
||||
startIndex = it - xValues.begin();
|
||||
if ( startIndex > 0 ) startIndex--;
|
||||
}
|
||||
|
||||
const bool removeInterpolatedValues = false;
|
||||
|
||||
// Use lower_bound to find the first element that is not less than the interpolation value using a threshold that is larger than the
|
||||
// threshold used in XComparator::equals
|
||||
XValueType threshold = 1.0e-6 * xValues.back();
|
||||
auto it = std::lower_bound( xValues.begin(), xValues.end(), interpolationXValue - threshold );
|
||||
if ( it == xValues.end() ) return HUGE_VAL;
|
||||
|
||||
size_t startIndex = it - xValues.begin();
|
||||
if ( startIndex > 0 ) startIndex--;
|
||||
|
||||
for ( size_t firstI = startIndex; firstI < xValues.size(); firstI++ )
|
||||
{
|
||||
if ( XComparator::equals( xValues.at( firstI ), interpolationXValue ) )
|
||||
@ -307,3 +354,17 @@ double RiaCurveMerger<XValueType>::interpolatedYValue( const XValueType&
|
||||
|
||||
return HUGE_VAL;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
template <typename XValueType>
|
||||
bool RiaCurveMerger<XValueType>::isMonotonicallyIncreasing( const std::vector<XValueType>& container )
|
||||
{
|
||||
return std::adjacent_find( container.begin(),
|
||||
container.end(),
|
||||
[]( const auto& a, const auto& b )
|
||||
{
|
||||
return b < a; // Returns true if not monotonically increasing
|
||||
} ) == container.end();
|
||||
}
|
||||
|
@ -208,3 +208,27 @@ TEST( RiaTimeHistoryCurveMergerTest, NoTimeStepOverlap )
|
||||
EXPECT_EQ( 0, static_cast<int>( curveMerger.validIntervalsForAllXValues().size() ) );
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
///
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
TEST( RiaTimeHistoryCurveMergerTest, SharedXValues )
|
||||
{
|
||||
std::vector<double> valuesA{ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 };
|
||||
std::vector<double> valuesB{ 10, 20, 30, 40, 50, 60, 70 };
|
||||
std::vector<time_t> timeSteps{ 1, 2, 3, 4, 5, 6, 7 };
|
||||
|
||||
RiaTimeHistoryCurveMerger interpolate;
|
||||
interpolate.addCurveData( timeSteps, valuesA );
|
||||
interpolate.addCurveData( timeSteps, valuesB );
|
||||
interpolate.computeInterpolatedValues( true );
|
||||
|
||||
auto interpolatedTimeSteps = interpolate.allXValues();
|
||||
EXPECT_TRUE( std::equal( timeSteps.begin(), timeSteps.end(), interpolatedTimeSteps.begin() ) );
|
||||
|
||||
auto generatedYValuesA = interpolate.interpolatedYValuesForAllXValues( 0 );
|
||||
EXPECT_TRUE( std::equal( valuesA.begin(), valuesA.end(), generatedYValuesA.begin() ) );
|
||||
|
||||
auto generatedYValuesB = interpolate.interpolatedYValuesForAllXValues( 1 );
|
||||
EXPECT_TRUE( std::equal( valuesB.begin(), valuesB.end(), generatedYValuesB.begin() ) );
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user