From 915e951a644beb839e4c75c97180f10f16313a49 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 23 Oct 2026 09:36:19 +0200 Subject: [PATCH] #13684: Add Plot 1-SGAS option to relative permeability plot Adds a "Plot 1-SGAS" checkbox to the relative permeability plot panel. When enabled (only available for two-phase gas-water systems), gas curves (KRG, KROG, PCOG/PCGW) are plotted against (1 - SGAS) instead of SGAS, aligning the gas saturation axis with the water saturation axis, matching normal relperm/capillary pressure plotting practice. Share the saturation transform between plotting and Show Plot Data export via a new applyOneMinusSgasTransform() helper, so the exported ascii data matches the rendered curves when the Plot 1-SGAS option is enabled. --- .../RiuRelativePermeabilityPlotPanel.cpp | 89 +++++++++++++++++-- .../RiuRelativePermeabilityPlotPanel.h | 10 ++- 2 files changed, 89 insertions(+), 10 deletions(-) diff --git a/ApplicationLibCode/UserInterface/RiuRelativePermeabilityPlotPanel.cpp b/ApplicationLibCode/UserInterface/RiuRelativePermeabilityPlotPanel.cpp index 8b6ffd1715..163f0a6bdb 100644 --- a/ApplicationLibCode/UserInterface/RiuRelativePermeabilityPlotPanel.cpp +++ b/ApplicationLibCode/UserInterface/RiuRelativePermeabilityPlotPanel.cpp @@ -132,6 +132,7 @@ RiuRelativePermeabilityPlotPanel::RiuRelativePermeabilityPlotPanel( QWidget* par , m_showScaledCheckBox( nullptr ) , m_fixedXAxisCheckBox( nullptr ) , m_fixedLeftYAxisCheckBox( nullptr ) + , m_plotOneMinusSgasCheckBox( nullptr ) , m_trackerPlotMarker( nullptr ) { @@ -186,6 +187,10 @@ RiuRelativePermeabilityPlotPanel::RiuRelativePermeabilityPlotPanel( QWidget* par m_showScaledCheckBox = new QCheckBox( "Show Scaled" ); m_fixedXAxisCheckBox = new QCheckBox( "Fixed [0, 1] X-axis" ); m_fixedLeftYAxisCheckBox = new QCheckBox( "Fixed [0, 1] Kr-axis" ); + m_plotOneMinusSgasCheckBox = new QCheckBox( "Plot 1-SGAS" ); + m_plotOneMinusSgasCheckBox->setToolTip( + "Plot gas curves (and PCGW) as a function of (1 - SGAS), aligning the gas saturation axis with the water saturation axis. " + "Only available for two-phase gas-water systems." ); m_fixedXAxisCheckBox->setChecked( true ); m_fixedLeftYAxisCheckBox->setChecked( true ); @@ -204,6 +209,7 @@ RiuRelativePermeabilityPlotPanel::RiuRelativePermeabilityPlotPanel( QWidget* par leftLayout->addWidget( m_showUnscaledCheckBox ); leftLayout->addWidget( m_fixedXAxisCheckBox ); leftLayout->addWidget( m_fixedLeftYAxisCheckBox ); + leftLayout->addWidget( m_plotOneMinusSgasCheckBox ); leftLayout->addStretch( 1 ); QHBoxLayout* mainLayout = new QHBoxLayout(); @@ -221,6 +227,7 @@ RiuRelativePermeabilityPlotPanel::RiuRelativePermeabilityPlotPanel( QWidget* par connect( m_showScaledCheckBox, SIGNAL( stateChanged( int ) ), SLOT( slotSomeCheckBoxStateChanged( int ) ) ); connect( m_fixedXAxisCheckBox, SIGNAL( stateChanged( int ) ), SLOT( slotSomeCheckBoxStateChanged( int ) ) ); connect( m_fixedLeftYAxisCheckBox, SIGNAL( stateChanged( int ) ), SLOT( slotSomeCheckBoxStateChanged( int ) ) ); + connect( m_plotOneMinusSgasCheckBox, SIGNAL( stateChanged( int ) ), SLOT( slotSomeCheckBoxStateChanged( int ) ) ); slotShowCurveSelectionWidgets( showCurveSelection->checkState() ); @@ -280,6 +287,7 @@ void RiuRelativePermeabilityPlotPanel::setPlotData( RiaDefines::EclipseUnitSyste m_availablePhases = availablePhases; updateCheckboxTexts(); + updatePlotOneMinusSgasCheckBoxState(); plotUiSelectedCurves(); } @@ -330,6 +338,7 @@ void RiuRelativePermeabilityPlotPanel::clearPlot() &m_myPlotMarkers, false, false, + false, m_availablePhases ); } @@ -371,6 +380,7 @@ void RiuRelativePermeabilityPlotPanel::plotUiSelectedCurves() &m_myPlotMarkers, m_showScaledCheckBox->isChecked(), m_showUnscaledCheckBox->isChecked(), + m_plotOneMinusSgasCheckBox->isChecked(), m_availablePhases ); } @@ -436,6 +446,7 @@ void RiuRelativePermeabilityPlotPanel::plotCurvesInQwt( RiaDefines::EclipseUnitS std::vector* myPlotMarkers, bool showScaled, bool showUnscaled, + bool plotOneMinusSgas, const std::set& availablePhases ) { bool skipUnscaledLegends = showScaled && showUnscaled; @@ -458,11 +469,18 @@ void RiuRelativePermeabilityPlotPanel::plotCurvesInQwt( RiaDefines::EclipseUnitS const QColor waterColor = RiuGuiTheme::getColorByVariableName( "curveColorWater" ); const QColor gasColor = RiuGuiTheme::getColorByVariableName( "curveColorGas" ); + // Only apply the 1-SGAS transformation for two-phase gas-water systems + const bool applyOneMinusSgas = plotOneMinusSgas && RiaPhaseTools::isTwoPhaseGasWater( availablePhases ); + + // Use a local, possibly saturation-transformed, copy of the curves for plotting. The same transform is also + // applied when generating the exported ascii data, see asciiDataForUiSelectedCurves(), so that the two stay in sync. + const std::vector curvesToPlot = applyOneMinusSgasTransform( curveArr, applyOneMinusSgas ); + bool shouldEnableRightYAxis = false; - for ( size_t i = 0; i < curveArr.size(); i++ ) + for ( size_t i = 0; i < curvesToPlot.size(); i++ ) { - const RigFlowDiagDefines::RelPermCurve& curve = curveArr[i]; + const RigFlowDiagDefines::RelPermCurve& curve = curvesToPlot[i]; const auto unscaledCurve = ( curve.epsMode == RigFlowDiagDefines::RelPermCurve::EPS_OFF ); @@ -546,7 +564,8 @@ void RiuRelativePermeabilityPlotPanel::plotCurvesInQwt( RiaDefines::EclipseUnitS if ( curve.ident == RigFlowDiagDefines::RelPermCurve::KRG || curve.ident == RigFlowDiagDefines::RelPermCurve::KROG || curve.ident == RigFlowDiagDefines::RelPermCurve::PCOG ) { - addCurveConstSaturationIntersectionMarker( curve, sgas, gasColor, plotOnWhichYAxis, plot, myPlotMarkers, &points, &axes ); + const double effectiveSgas = applyOneMinusSgas ? 1.0 - sgas : sgas; + addCurveConstSaturationIntersectionMarker( curve, effectiveSgas, gasColor, plotOnWhichYAxis, plot, myPlotMarkers, &points, &axes ); } } } @@ -571,7 +590,9 @@ void RiuRelativePermeabilityPlotPanel::plotCurvesInQwt( RiaDefines::EclipseUnitS } if ( sgas != HUGE_VAL ) { - addVerticalSaturationMarkerLine( sgas, RiaResultNames::sgas(), gasColor, plot, myPlotMarkers ); + const double effectiveSgas = applyOneMinusSgas ? 1.0 - sgas : sgas; + const QString sgasLabel = applyOneMinusSgas ? "1-" + RiaResultNames::sgas() : RiaResultNames::sgas(); + addVerticalSaturationMarkerLine( effectiveSgas, sgasLabel, gasColor, plot, myPlotMarkers ); } if ( logScaleLeftAxis ) @@ -635,7 +656,7 @@ void RiuRelativePermeabilityPlotPanel::plotCurvesInQwt( RiaDefines::EclipseUnitS } plot->setTitle( titleStr ); - plot->setAxisTitle( QwtAxis::XBottom, determineXAxisTitleFromCurveCollection( curveArr ) ); + plot->setAxisTitle( QwtAxis::XBottom, determineXAxisTitleFromCurveCollection( curveArr, applyOneMinusSgas ) ); plot->setAxisTitle( QwtAxis::YLeft, "Kr" ); plot->setAxisTitle( QwtAxis::YRight, QString( "Pc [%1]" ).arg( RiaEclipseUnitTools::unitStringPressure( unitSystem ) ) ); plot->replot(); @@ -671,7 +692,8 @@ QwtPlotCurve* RiuRelativePermeabilityPlotPanel::getLegendCurve( QString title, b //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -QString RiuRelativePermeabilityPlotPanel::determineXAxisTitleFromCurveCollection( const std::vector& curveArr ) +QString RiuRelativePermeabilityPlotPanel::determineXAxisTitleFromCurveCollection( const std::vector& curveArr, + bool plotOneMinusSgas ) { bool sawWater = false; bool sawGas = false; @@ -682,17 +704,48 @@ QString RiuRelativePermeabilityPlotPanel::determineXAxisTitleFromCurveCollection if ( curve.isGasCurve() ) sawGas = true; } + const QString gasAxisLabel = plotOneMinusSgas ? "1-SGAS" : "SGAS"; + QString title = ""; if ( sawWater && sawGas ) - title = "SWAT/SGAS"; + title = "SWAT/" + gasAxisLabel; else if ( sawWater ) title = "SWAT"; else if ( sawGas ) - title = "SGAS"; + title = gasAxisLabel; return title; } +//-------------------------------------------------------------------------------------------------- +/// Returns a copy of curveArr where the saturation values of the gas curves are transformed to 1-SGAS when +/// applyTransform is true. Used both when plotting the curves and when generating the exported ascii data, so +/// that the two always stay in sync. +//-------------------------------------------------------------------------------------------------- +std::vector + RiuRelativePermeabilityPlotPanel::applyOneMinusSgasTransform( const std::vector& curveArr, + bool applyTransform ) +{ + if ( !applyTransform ) return curveArr; + + std::vector transformedCurves = curveArr; + for ( RigFlowDiagDefines::RelPermCurve& curve : transformedCurves ) + { + if ( !curve.isGasCurve() ) continue; + + for ( double& saturationVal : curve.saturationVals ) + { + saturationVal = 1.0 - saturationVal; + } + + // Keep x ascending, as required by the interpolation used for the intersection markers + std::reverse( curve.saturationVals.begin(), curve.saturationVals.end() ); + std::reverse( curve.yVals.begin(), curve.yVals.end() ); + } + + return transformedCurves; +} + //-------------------------------------------------------------------------------------------------- /// Add a vertical labeled marker line at the specified saturation value //-------------------------------------------------------------------------------------------------- @@ -794,6 +847,10 @@ QString RiuRelativePermeabilityPlotPanel::asciiDataForUiSelectedCurves() const { std::vector selectedCurves = gatherUiSelectedCurves(); + // Apply the same saturation transform as used when plotting, so the exported data matches the graph + const bool applyOneMinusSgas = m_plotOneMinusSgasCheckBox->isChecked() && RiaPhaseTools::isTwoPhaseGasWater( m_availablePhases ); + selectedCurves = applyOneMinusSgasTransform( selectedCurves, applyOneMinusSgas ); + QString outTxt; // Info header @@ -809,7 +866,7 @@ QString RiuRelativePermeabilityPlotPanel::asciiDataForUiSelectedCurves() const if ( curve.isWaterCurve() ) outTxt += "SWAT"; else if ( curve.isGasCurve() ) - outTxt += "SGAS"; + outTxt += applyOneMinusSgas ? "1-SGAS" : "SGAS"; else outTxt += "Saturation"; outTxt += "\t"; @@ -868,6 +925,19 @@ void RiuRelativePermeabilityPlotPanel::updateCheckboxTexts() } } +//-------------------------------------------------------------------------------------------------- +/// Only allow the "Plot 1-SGAS" option for two-phase gas-water systems +//-------------------------------------------------------------------------------------------------- +void RiuRelativePermeabilityPlotPanel::updatePlotOneMinusSgasCheckBoxState() +{ + const bool enable = RiaPhaseTools::isTwoPhaseGasWater( m_availablePhases ); + if ( !enable ) + { + m_plotOneMinusSgasCheckBox->setChecked( false ); + } + m_plotOneMinusSgasCheckBox->setEnabled( enable ); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -910,6 +980,7 @@ void RiuRelativePermeabilityPlotPanel::slotShowCurveSelectionWidgets( int state m_logarithmicScaleKrAxisCheckBox->setVisible( setVisible ); m_fixedXAxisCheckBox->setVisible( setVisible ); m_fixedLeftYAxisCheckBox->setVisible( setVisible ); + m_plotOneMinusSgasCheckBox->setVisible( setVisible ); } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/UserInterface/RiuRelativePermeabilityPlotPanel.h b/ApplicationLibCode/UserInterface/RiuRelativePermeabilityPlotPanel.h index 0378c8de9c..364a190b7d 100644 --- a/ApplicationLibCode/UserInterface/RiuRelativePermeabilityPlotPanel.h +++ b/ApplicationLibCode/UserInterface/RiuRelativePermeabilityPlotPanel.h @@ -88,11 +88,18 @@ private: std::vector* myPlotMarkers, bool showScaled, bool showUnscaled, + bool plotOneMinusSgas, const std::set& availablePhases ); static QwtPlotCurve* getLegendCurve( QString title, bool scaled ); - static QString determineXAxisTitleFromCurveCollection( const std::vector& curveArr ); + static QString determineXAxisTitleFromCurveCollection( const std::vector& curveArr, + bool plotOneMinusSgas ); + + static std::vector + applyOneMinusSgasTransform( const std::vector& curveArr, bool applyTransform ); + + void updatePlotOneMinusSgasCheckBoxState(); static void addVerticalSaturationMarkerLine( double saturationValue, QString label, @@ -156,6 +163,7 @@ private: QCheckBox* m_logarithmicScaleKrAxisCheckBox; QCheckBox* m_fixedXAxisCheckBox; QCheckBox* m_fixedLeftYAxisCheckBox; + QCheckBox* m_plotOneMinusSgasCheckBox; std::unique_ptr m_plotUpdater; };