Implement stacked well log curves

This commit is contained in:
Gaute Lindkvist
2020-06-23 15:35:17 +02:00
parent 3202a5f85d
commit 6856597770
14 changed files with 204 additions and 15 deletions

View File

@@ -165,11 +165,14 @@ void RimWellFlowRateCurve::onLoadDataAndUpdate( bool updateParentPlot )
{
m_qwtPlotCurve->setTitle( createCurveAutoName() );
if ( updateParentPlot )
{
RimWellLogTrack* track = nullptr;
this->firstAncestorOrThisOfTypeAsserted( track );
track->updateStackedCurveData();
updateZoomInParentPlot();
}
if ( m_parentQwtPlot ) m_parentQwtPlot->replot();
}

View File

@@ -87,6 +87,7 @@ RimPlotAxisProperties::RimPlotAxisProperties()
CAF_PDM_InitField(&m_isAutoZoom, "AutoZoom", true, "Set Range Automatically", "", "", "");
CAF_PDM_InitField(&isLogarithmicScaleEnabled, "LogarithmicScale", false, "Logarithmic Scale", "", "", "");
CAF_PDM_InitField(&m_isAxisInverted, "AxisInverted", false, "Invert Axis", "", "", "");
CAF_PDM_InitField(&m_stackCurves, "StackCurves", false, "Stack Curves", "", "", "");
CAF_PDM_InitFieldNoDefault(&m_titlePositionEnum, "TitlePosition", "Title Position", "", "", "");
@@ -187,6 +188,7 @@ void RimPlotAxisProperties::defineUiOrdering( QString uiConfigName, caf::PdmUiOr
scaleGroup.add( &isLogarithmicScaleEnabled );
scaleGroup.add( &m_isAxisInverted );
}
scaleGroup.add( &m_stackCurves );
scaleGroup.add( &numberFormat );
if ( numberFormat() != NUMBER_FORMAT_AUTO )
@@ -347,6 +349,14 @@ void RimPlotAxisProperties::setAxisInverted( bool inverted )
m_isAxisInverted = inverted;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimPlotAxisProperties::stackCurves() const
{
return m_stackCurves();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -399,7 +409,7 @@ void RimPlotAxisProperties::fieldChangedByUi( const caf::PdmFieldHandle* changed
this->firstAncestorOrThisOfType( parentPlot );
if ( parentPlot )
{
if ( changedField == &isLogarithmicScaleEnabled )
if ( changedField == &isLogarithmicScaleEnabled || changedField == &m_stackCurves )
{
parentPlot->loadDataAndUpdate();
}

View File

@@ -72,6 +72,7 @@ public:
void setAutoZoom( bool enableAutoZoom );
bool isAxisInverted() const;
void setAxisInverted( bool inverted );
bool stackCurves() const;
std::vector<RimPlotAxisAnnotation*> annotations() const;
void appendAnnotation( RimPlotAxisAnnotation* annotation );
@@ -114,6 +115,7 @@ private:
caf::PdmField<bool> m_displayUnitText;
caf::PdmField<bool> m_isAutoZoom;
caf::PdmField<bool> m_isAxisInverted;
caf::PdmField<bool> m_stackCurves;
caf::PdmField<QString> m_name;
QwtPlot::Axis m_axis;

View File

@@ -40,5 +40,3 @@ void RimPlotAxisPropertiesInterface::LegendTickmarkCountEnum::setUp()
setDefault( RimPlotAxisPropertiesInterface::LegendTickmarkCount::TICKMARK_DEFAULT );
}
} // namespace caf

View File

@@ -18,6 +18,7 @@
#include "RimPlotCurve.h"
#include "RiaColorTools.h"
#include "RiaCurveDataTools.h"
#include "RiaGuiApplication.h"
#include "RiaPreferences.h"
@@ -770,7 +771,7 @@ void RimPlotCurve::updateCurveAppearance()
if ( m_qwtPlotCurve )
{
QColor fillColor( m_fillColor.value().rByte(), m_fillColor.value().gByte(), m_fillColor.value().bByte() );
fillColor.setAlpha( 130 );
fillColor = RiaColorTools::blendQColors( fillColor, QColor( Qt::white ), 3, 1 );
QBrush fillBrush( fillColor, m_fillStyle() );
m_qwtPlotCurve->setAppearance( m_lineStyle(), m_curveInterpolation(), m_curveThickness(), curveColor, fillBrush );
m_qwtPlotCurve->setSymbol( symbol );
@@ -983,6 +984,22 @@ void RimPlotCurve::resetAppearance()
setSymbolSkipDistance( 10 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Qt::BrushStyle RimPlotCurve::fillStyle() const
{
return m_fillStyle();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPlotCurve::setFillStyle( Qt::BrushStyle brushStyle )
{
m_fillStyle = brushStyle;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@@ -80,6 +80,8 @@ public:
void setSymbolSize( int sizeInPixels );
void setLineThickness( int thickness );
void resetAppearance();
Qt::BrushStyle fillStyle() const;
void setFillStyle( Qt::BrushStyle brushStyle );
bool isCurveVisible() const;
void setCurveVisibility( bool visible );

View File

@@ -460,6 +460,7 @@ void RimWellLogTrack::calculateYZoomRange()
//--------------------------------------------------------------------------------------------------
void RimWellLogTrack::updateXZoom()
{
const double eps = 1.0e-8;
if ( !m_plotWidget ) return;
calculateXZoomRange();
@@ -469,6 +470,13 @@ void RimWellLogTrack::updateXZoom()
m_visibleXRangeMin = m_availableXRangeMin;
m_visibleXRangeMax = m_availableXRangeMax;
// Consider auto zooming to full range [0..1] range
if ( -eps < m_visibleXRangeMin && m_visibleXRangeMin < 0.25 && 0.75 < m_visibleXRangeMax &&
m_visibleXRangeMax < 1.0 + eps && !m_isLogarithmicScaleEnabled )
{
m_visibleXRangeMin = 0.0;
m_visibleXRangeMax = 1.0;
}
computeAndSetXRangeMinForLogarithmicScale();
updateEditors();
}
@@ -709,6 +717,25 @@ void RimWellLogTrack::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
updateParentLayout();
RiuPlotMainWindowTools::refreshToolbars();
}
else if ( changedField == &m_stackCurves )
{
updateStackedCurveData();
m_isAutoScaleXEnabled = true;
updateXZoom();
m_plotWidget->scheduleReplot();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimWellLogTrack::childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField )
{
if ( m_stackCurves )
{
updateStackedCurveData();
}
}
//--------------------------------------------------------------------------------------------------
@@ -2081,6 +2108,7 @@ void RimWellLogTrack::uiOrderingForXAxisSettings( caf::PdmUiOrdering& uiOrdering
gridGroup->add( &m_visibleXRangeMin );
gridGroup->add( &m_visibleXRangeMax );
gridGroup->add( &m_xAxisGridVisibility );
gridGroup->add( &m_stackCurves );
// TODO Revisit if these settings are required
// See issue https://github.com/OPM/ResInsight/issues/4367
@@ -2258,6 +2286,8 @@ std::vector<QString> RimWellLogTrack::formationNamesVector( RimCase* rimCase )
//--------------------------------------------------------------------------------------------------
void RimWellLogTrack::updateStackedCurveData()
{
const double eps = 1.0e-8;
RimWellLogPlot* wellLogPlot;
firstAncestorOrThisOfTypeAsserted( wellLogPlot );
@@ -2270,6 +2300,13 @@ void RimWellLogTrack::updateStackedCurveData()
reverseOrder = true;
}
// Reset all curves
for ( auto curve : visibleCurves() )
{
curve->loadDataAndUpdate( false );
}
// Stack the curves that are meant to be stacked
std::map<int, std::vector<RimWellLogCurve*>> stackedCurves = visibleStackedCurves();
for ( auto groupCurvePair : stackedCurves )
@@ -2299,8 +2336,8 @@ void RimWellLogTrack::updateStackedCurveData()
auto it = std::lower_bound( allDepthValues.begin(),
allDepthValues.end(),
depth,
[reverseOrder]( double lhs, double rhs ) {
return reverseOrder ? rhs < lhs : lhs < rhs;
[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.
@@ -2331,6 +2368,12 @@ 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 );
zPos -= 1.0;

View File

@@ -250,6 +250,7 @@ private:
void doRemoveFromCollection() override;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
void childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField ) override;
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions,
bool* useOptionsOnly ) override;

View File

@@ -338,6 +338,43 @@ const std::vector<time_t>& RimSummaryCurve::timeStepsY() const
return reader->timeSteps( addr );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimSummaryCurve::yValueAtTimeT( time_t time ) const
{
const std::vector<time_t>& timeSteps = timeStepsY();
const std::vector<double> values = valuesY();
if ( timeSteps.empty() || time < timeSteps.front() || time > timeSteps.back() )
return std::numeric_limits<double>::infinity();
for ( size_t i = 0; i < timeSteps.size(); ++i )
{
if ( timeSteps[i] == time )
{
return values[i];
}
else if ( i < timeSteps.size() - 1u && timeSteps[i] < time && time < timeSteps[i + 1] )
{
if ( m_curveInterpolation == RiuQwtPlotCurve::INTERPOLATION_STEP_LEFT )
{
return values[i + 1];
}
else
{
double slope = 0.0;
if ( timeSteps[i + 1] != timeSteps[i] )
{
slope = ( values[i + 1] - values[i] ) / (double)( timeSteps[i + 1] - timeSteps[i] );
}
return slope * ( time - timeSteps[i] ) + values[i];
}
}
}
return std::numeric_limits<double>::infinity();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@@ -63,6 +63,7 @@ public:
void setLeftOrRightAxisY( RiaDefines::PlotAxis plotAxis );
RiaDefines::PlotAxis axisY() const;
const std::vector<time_t>& timeStepsY() const;
double yValueAtTimeT( time_t time ) const;
// X Axis functions
void setSummaryCaseX( RimSummaryCase* sumCase );

View File

@@ -1333,6 +1333,71 @@ void RimSummaryPlot::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField )
{
updateStackedCurveData();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateStackedCurveData()
{
if ( m_leftYAxisProperties->stackCurves() ) updateStackedCurveDataForAxis( RiaDefines::PlotAxis::PLOT_AXIS_LEFT );
if ( m_rightYAxisProperties->stackCurves() ) updateStackedCurveDataForAxis( RiaDefines::PlotAxis::PLOT_AXIS_RIGHT );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSummaryPlot::updateStackedCurveDataForAxis( RiaDefines::PlotAxis plotAxis )
{
// Reset all curves
for ( RimSummaryCurve* curve : visibleSummaryCurvesForAxis( plotAxis ) )
{
curve->loadDataAndUpdate( false );
}
RimPlotAxisProperties* axisProperties = yAxisPropertiesLeftOrRight( plotAxis );
if ( axisProperties->stackCurves() )
{
// Z-position of curve, to draw them in correct order
double zPos = -10000.0;
std::vector<time_t> allTimeSteps;
for ( RimSummaryCurve* curve : visibleSummaryCurvesForAxis( plotAxis ) )
{
allTimeSteps.insert( allTimeSteps.end(), curve->timeStepsY().begin(), curve->timeStepsY().end() );
}
std::sort( allTimeSteps.begin(), allTimeSteps.end() );
allTimeSteps.erase( std::unique( allTimeSteps.begin(), allTimeSteps.end() ), allTimeSteps.end() );
std::vector<double> allStackedValues( allTimeSteps.size(), 0.0 );
for ( RimSummaryCurve* curve : visibleSummaryCurvesForAxis( plotAxis ) )
{
for ( size_t i = 0; i < allTimeSteps.size(); ++i )
{
double value = curve->yValueAtTimeT( allTimeSteps[i] );
if ( value != std::numeric_limits<double>::infinity() )
{
allStackedValues[i] += value;
}
}
// Apply a area filled style if it isn't already set
if ( curve->fillStyle() == Qt::NoBrush )
{
curve->setFillStyle( Qt::SolidPattern );
}
curve->setOverrideCurveDataY( allTimeSteps, allStackedValues );
curve->setZOrder( zPos );
zPos -= 1.0;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@@ -193,6 +193,10 @@ protected:
// Overridden PDM methods
caf::PdmFieldHandle* userDescriptionField() override;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
void childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField ) override;
void updateStackedCurveData();
void updateStackedCurveDataForAxis( RiaDefines::PlotAxis plotAxis );
void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "" ) override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void onLoadDataAndUpdate() override;

View File

@@ -336,8 +336,6 @@ void RigWellLogCurveData::interpolateSegment( RiaDefines::DepthTypeEnum resampli
size_t secondIndex = firstIndex + 1;
if ( secondIndex >= depthIt->second.size() ) return;
double depth0 = depthIt->second[firstIndex];
double depth1 = depthIt->second[secondIndex];
double x0 = m_xValues[firstIndex];
@@ -381,7 +379,6 @@ cvf::ref<RigWellLogCurveData> RigWellLogCurveData::calculateResampledCurveData(
std::vector<double> xValues;
bool isTVDAvailable = false;
std::map<RiaDefines::DepthTypeEnum, std::vector<double>> resampledDepths;
auto depthIt = m_depths.find( resamplingDepthType );
@@ -393,18 +390,21 @@ cvf::ref<RigWellLogCurveData> RigWellLogCurveData::calculateResampledCurveData(
bool reverseOrder = resamplingDepthType == RiaDefines::DepthTypeEnum::CONNECTION_NUMBER;
size_t segmentSearchStartIdx = 0;
for ( double depth : depths )
for ( auto depth : depths )
{
bool foundPoint = false;
if ( isLeftOf( depth, depthIt->second.front(), reverseOrder, eps ) )
{
// 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
{
@@ -424,6 +424,8 @@ cvf::ref<RigWellLogCurveData> RigWellLogCurveData::calculateResampledCurveData(
}
}
segmentSearchStartIdx = segmentStartIdx + 1;
foundPoint = true;
break;
}
else if ( segmentStartIdx < depthIt->second.size() - 1 &&
isLeftOf( depthIt->second[segmentStartIdx], depth, reverseOrder, eps ) &&
@@ -433,9 +435,12 @@ cvf::ref<RigWellLogCurveData> RigWellLogCurveData::calculateResampledCurveData(
{
interpolateSegment( resamplingDepthType, depth, segmentStartIdx, xValues, resampledDepths, eps );
segmentSearchStartIdx = segmentStartIdx;
foundPoint = true;
break;
}
}
}
CAF_ASSERT( foundPoint );
}
resampledDepths.insert( std::make_pair( resamplingDepthType, depths ) );

View File

@@ -2,6 +2,7 @@
#include "cafAssert.h"
#include "cafPdmBase.h"
#include "cafSignalHandle.h"
#include <QString>
@@ -19,7 +20,7 @@ class PdmChildArrayFieldHandle;
//==================================================================================================
/// The base class of all objects
//==================================================================================================
class PdmObjectHandle
class PdmObjectHandle : public SignalObserver
{
public:
PdmObjectHandle();