#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.
This commit is contained in:
Magne Sjaastad authored and GitHub committed 2026-10-23 09:36:19 +02:00
1 parent 7222d6360e
commit 915e951a64
2 files changed
+89 -10

No files matched your search

@@ -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<QwtPlotMarker*>* myPlotMarkers,
bool showScaled,
bool showUnscaled,
bool plotOneMinusSgas,
const std::set<RiaDefines::PhaseType>& 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<RigFlowDiagDefines::RelPermCurve> 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<RigFlowDiagDefines::RelPermCurve>& curveArr )
QString RiuRelativePermeabilityPlotPanel::determineXAxisTitleFromCurveCollection( const std::vector<RigFlowDiagDefines::RelPermCurve>& 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<RigFlowDiagDefines::RelPermCurve>
RiuRelativePermeabilityPlotPanel::applyOneMinusSgasTransform( const std::vector<RigFlowDiagDefines::RelPermCurve>& curveArr,
bool applyTransform )
{
if ( !applyTransform ) return curveArr;
std::vector<RigFlowDiagDefines::RelPermCurve> 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<RigFlowDiagDefines::RelPermCurve> 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 );
}
//--------------------------------------------------------------------------------------------------
@@ -88,11 +88,18 @@ private:
std::vector<QwtPlotMarker*>* myPlotMarkers,
bool showScaled,
bool showUnscaled,
bool plotOneMinusSgas,
const std::set<RiaDefines::PhaseType>& availablePhases );
static QwtPlotCurve* getLegendCurve( QString title, bool scaled );
static QString determineXAxisTitleFromCurveCollection( const std::vector<RigFlowDiagDefines::RelPermCurve>& curveArr );
static QString determineXAxisTitleFromCurveCollection( const std::vector<RigFlowDiagDefines::RelPermCurve>& curveArr,
bool plotOneMinusSgas );
static std::vector<RigFlowDiagDefines::RelPermCurve>
applyOneMinusSgasTransform( const std::vector<RigFlowDiagDefines::RelPermCurve>& 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<RiuRelativePermeabilityPlotUpdater> m_plotUpdater;
};