#6304 Improve stacked curve interpolation

* We no longer require the depth data to be well ordered.
This commit is contained in:
Gaute Lindkvist
2020-08-24 15:00:58 +02:00
committed by Magne Sjaastad
parent f96a597321
commit 9eb79fbb0e
2 changed files with 86 additions and 91 deletions

View File

@@ -475,10 +475,11 @@ void RimWellLogTrack::updateXZoom()
m_visibleXRangeMin = m_availableXRangeMin;
m_visibleXRangeMax = m_availableXRangeMax;
// Set min limit to 0.0 for stacked curves
if ( !visibleStackedCurves().empty() && !m_isLogarithmicScaleEnabled )
{
m_visibleXRangeMin = 0.0;
// Try to ensure we include the base line whether the values are negative or positive.
m_visibleXRangeMin = std::min( m_visibleXRangeMin(), 0.0 );
m_visibleXRangeMax = std::max( m_visibleXRangeMax(), 0.0 );
}
computeAndSetXRangeMinForLogarithmicScale();
updateEditors();
@@ -2371,32 +2372,32 @@ std::vector<QString> RimWellLogTrack::formationNamesVector( RimCase* rimCase )
//--------------------------------------------------------------------------------------------------
void RimWellLogTrack::updateStackedCurveData()
{
const double eps = 1.0e-8;
RimDepthTrackPlot* wellLogPlot;
firstAncestorOrThisOfTypeAsserted( wellLogPlot );
RimWellLogPlot::DepthTypeEnum depthType = wellLogPlot->depthType();
RiaDefines::DepthUnitType displayUnit = wellLogPlot->depthUnit();
bool reverseOrder = false;
RimWellLogPlot::DepthTypeEnum depthType = wellLogPlot->depthType();
RiaDefines::DepthUnitType displayUnit = wellLogPlot->depthUnit();
if ( depthType == RiaDefines::DepthTypeEnum::CONNECTION_NUMBER )
{
displayUnit = RiaDefines::DepthUnitType::UNIT_NONE;
reverseOrder = true;
displayUnit = RiaDefines::DepthUnitType::UNIT_NONE;
}
std::map<RiaDefines::PhaseType, size_t> curvePhaseCount;
// Reset all curves
for ( auto curve : visibleCurves() )
{
curve->loadDataAndUpdate( false );
curvePhaseCount[curve->phaseType()]++;
}
// Stack the curves that are meant to be stacked
std::map<int, std::vector<RimWellLogCurve*>> stackedCurves = visibleStackedCurves();
// Reset all stacked curves
for ( auto groupCurvePair : stackedCurves )
{
const std::vector<RimWellLogCurve*>& stackedCurvesInGroup = groupCurvePair.second;
for ( auto curve : stackedCurvesInGroup )
{
curve->loadDataAndUpdate( false );
curvePhaseCount[curve->phaseType()]++;
}
}
for ( auto groupCurvePair : stackedCurves )
{
int groupId = groupCurvePair.first;
@@ -2406,45 +2407,32 @@ void RimWellLogTrack::updateStackedCurveData()
// Z-position of curve, to draw them in correct order
double zPos = -10000.0 + 100.0 * static_cast<double>( groupId );
// Find common depths. We retain all depths from the first curve and insert ones that aren't already added.
std::vector<double> allDepthValues;
// We use the depths from the curve with the largest depth range.
// Trying to merge them is difficult since they may not be in order.
std::pair<double, double> maxDepthRange;
std::vector<double> allDepthValues;
for ( auto curve : stackedCurvesInGroup )
{
auto depths = curve->curveData()->depths( depthType );
if ( allDepthValues.empty() )
{
auto minmaxit = std::minmax_element( depths.begin(), depths.end() );
maxDepthRange = std::make_pair( *minmaxit.first, *minmaxit.second );
allDepthValues.insert( allDepthValues.end(), depths.begin(), depths.end() );
}
else
{
for ( double depth : depths )
auto minmaxit = std::minmax_element( depths.begin(), depths.end() );
std::pair<double, double> depthRange = std::make_pair( *minmaxit.first, *minmaxit.second );
if ( std::fabs( depthRange.second - depthRange.first ) >
std::fabs( maxDepthRange.second - maxDepthRange.first ) )
{
// Finds the first larger or equal depth.
auto it = std::lower_bound( allDepthValues.begin(),
allDepthValues.end(),
depth,
[eps, reverseOrder]( double lhs, double rhs ) {
return reverseOrder ? lhs - rhs > eps : rhs - lhs > eps;
} );
// Insert if there is no larger or equal depths or if the first equal or if it actually larger.
if ( it == allDepthValues.end() || std::fabs( depth - *it ) > 1.0e-8 )
{
allDepthValues.insert( it, depth );
}
maxDepthRange = depthRange;
allDepthValues = depths;
}
}
}
// The above doesn't sort nearly identical depths. The resampling below requires that.
if ( depthType == RiaDefines::DepthTypeEnum::CONNECTION_NUMBER )
{
std::sort( allDepthValues.begin(), allDepthValues.end(), std::greater<double>() );
}
else
{
std::sort( allDepthValues.begin(), allDepthValues.end() );
}
if ( allDepthValues.empty() ) continue;
@@ -2467,17 +2455,21 @@ void RimWellLogTrack::updateStackedCurveData()
auto plotDepthValues = tempCurveData.depthPlotValues( depthType, displayUnit );
auto polyLineStartStopIndices = tempCurveData.polylineStartStopIndices();
// Apply a area filled style if it isn't already set
if ( curve->fillStyle() == Qt::NoBrush )
{
curve->setFillStyle( Qt::SolidPattern );
}
curve->setOverrideCurveData( allStackedValues, plotDepthValues, polyLineStartStopIndices );
curve->setZOrder( zPos );
if ( curve->isStackedWithPhaseColors() )
if ( !dynamic_cast<RimWellFlowRateCurve*>( curve ) )
{
curve->assignStackColor( stackIndex, curvePhaseCount[curve->phaseType()] );
// Apply a area filled style if it isn't already set
if ( curve->fillStyle() == Qt::NoBrush )
{
curve->setFillStyle( Qt::SolidPattern );
}
if ( curve->isStackedWithPhaseColors() )
{
curve->assignStackColor( stackIndex, curvePhaseCount[curve->phaseType()] );
}
}
zPos -= 1.0;
}

View File

@@ -369,8 +369,13 @@ bool isLeftOf( double x1, double x2, bool reverseOrder, double eps )
return x2 - x1 > eps;
}
bool isRightOf( double x1, double x2, bool reverseOrder, double eps )
{
return isLeftOf( x2, x1, reverseOrder, eps );
}
//--------------------------------------------------------------------------------------------------
/// Assumes the data is well ordered
///
//--------------------------------------------------------------------------------------------------
cvf::ref<RigWellLogCurveData> RigWellLogCurveData::calculateResampledCurveData( RiaDefines::DepthTypeEnum resamplingDepthType,
const std::vector<double>& depths ) const
@@ -380,6 +385,7 @@ cvf::ref<RigWellLogCurveData> RigWellLogCurveData::calculateResampledCurveData(
std::vector<double> xValues;
std::map<RiaDefines::DepthTypeEnum, std::vector<double>> resampledDepths;
resampledDepths.insert( std::make_pair( resamplingDepthType, depths ) );
auto depthIt = m_depths.find( resamplingDepthType );
@@ -393,60 +399,57 @@ cvf::ref<RigWellLogCurveData> RigWellLogCurveData::calculateResampledCurveData(
for ( auto depth : depths )
{
bool foundPoint = false;
if ( isLeftOf( depth, depthIt->second.front(), reverseOrder, eps ) )
for ( size_t segmentStartIdx = segmentSearchStartIdx; segmentStartIdx < depthIt->second.size(); ++segmentStartIdx )
{
// Extrapolate from front two
interpolateSegment( resamplingDepthType, depth, 0, xValues, resampledDepths, eps );
foundPoint = true;
}
else if ( isLeftOf( depthIt->second.back(), depth, reverseOrder, eps ) )
{
// Extrapolate from end two
const size_t N = depthIt->second.size() - 1;
interpolateSegment( resamplingDepthType, depth, N - 1, xValues, resampledDepths, eps );
foundPoint = true;
}
else
{
for ( size_t segmentStartIdx = segmentSearchStartIdx; segmentStartIdx < depthIt->second.size();
++segmentStartIdx )
if ( std::fabs( depthIt->second[segmentStartIdx] - depth ) < eps ) // already have this depth point,
// reuse it
{
if ( std::fabs( depthIt->second[segmentStartIdx] - depth ) < eps ) // already have this depth point,
// reuse it
xValues.push_back( m_xValues[segmentStartIdx] );
// Copy all depth types for this segment
for ( auto depthTypeValuesPair : m_depths )
{
xValues.push_back( m_xValues[segmentStartIdx] );
for ( auto depthTypeValuesPair : m_depths )
if ( depthTypeValuesPair.first != resamplingDepthType )
{
if ( depthTypeValuesPair.first != resamplingDepthType )
{
resampledDepths[depthTypeValuesPair.first].push_back(
depthTypeValuesPair.second[segmentStartIdx] );
}
resampledDepths[depthTypeValuesPair.first].push_back( depthTypeValuesPair.second[segmentStartIdx] );
}
segmentSearchStartIdx = segmentStartIdx + 1;
}
segmentSearchStartIdx = segmentStartIdx + 1;
foundPoint = true;
break;
}
else if ( segmentStartIdx < depthIt->second.size() - 1 )
{
double minDepthSegment = std::min( depthIt->second[segmentStartIdx], depthIt->second[segmentStartIdx + 1] );
double maxDepthSegment = std::max( depthIt->second[segmentStartIdx], depthIt->second[segmentStartIdx + 1] );
if ( cvf::Math::valueInRange( depth, minDepthSegment, maxDepthSegment ) )
{
interpolateSegment( resamplingDepthType, depth, segmentStartIdx, xValues, resampledDepths, eps );
segmentSearchStartIdx = segmentStartIdx;
foundPoint = true;
break;
}
else if ( segmentStartIdx < depthIt->second.size() - 1 )
{
double minDepthSegment =
std::min( depthIt->second[segmentStartIdx], depthIt->second[segmentStartIdx + 1] );
double maxDepthSegment =
std::max( depthIt->second[segmentStartIdx], depthIt->second[segmentStartIdx + 1] );
if ( cvf::Math::valueInRange( depth, minDepthSegment, maxDepthSegment ) )
{
interpolateSegment( resamplingDepthType, depth, segmentStartIdx, xValues, resampledDepths, eps );
segmentSearchStartIdx = segmentStartIdx;
foundPoint = true;
break;
}
}
}
}
if ( !foundPoint )
{
if ( isLeftOf( depth, depthIt->second.front(), reverseOrder, eps ) )
{
// Extrapolate from front two
interpolateSegment( resamplingDepthType, depth, 0, xValues, resampledDepths, eps );
foundPoint = true;
}
else if ( isRightOf( depth, depthIt->second.back(), reverseOrder, eps ) )
{
// Extrapolate from end two
const size_t N = depthIt->second.size() - 1;
interpolateSegment( resamplingDepthType, depth, N - 1, xValues, resampledDepths, eps );
foundPoint = true;
}
}
CAF_ASSERT( foundPoint );
}
resampledDepths.insert( std::make_pair( resamplingDepthType, depths ) );
reSampledData->setValuesAndDepths( xValues, resampledDepths, m_rkbDiff, m_depthUnit, true );
return reSampledData;
}