Files
ResInsight/ApplicationLibCode/UserInterface/RiuRelativePermeabilityPlotPanel.cpp
T
Magne Sjaastad 56e98ba1c4 #14476 ApplicationLibCode: Replace CVF_ASSERT with CAF_ASSERT
Migrate all assert macros in ApplicationLibCode to CAF_ASSERT and remove every
use of cvfAssert.h.

CVF_ASSERT is replaced one to one. CVF_TIGHT_ASSERT is also replaced by
CAF_ASSERT, which is semantically exact: CVF_ENABLE_TIGHT_ASSERTS is 1 only
under _DEBUG, and that is what CAF_ASSERT now does. The two CVF_FAIL_MSG sites
become CAF_ASSERT( false && "message" ), preserving the message with the idiom
already used elsewhere in the code base.

Counts before and after: CVF_ASSERT 1044 to 0, CVF_TIGHT_ASSERT 66 to 0,
CVF_FAIL_MSG 2 to 0, cvfAssert.h references 154 to 0.

Include handling: files that included cvfAssert.h directly now include
cafAssert.h instead, includes left dead by the migration are removed, and files
that were relying on cvfAssert.h transitively get an explicit cafAssert.h. Files
that reach cafAssert.h through another caf header are left unchanged; a missing
include here is a compile error, not a silently disabled assert.

ResultStatisticsCache links only LibCore and therefore had no path to
cafAssert.h. Add the cafPdmCore directory as a private include path rather than
linking the library, since cafAssert.h is header only.

Note that this stops these asserts from firing in Release and RelWithDebInfo,
where CVF_ASSERT was previously active.
2026-08-07 15:05:57 +02:00

1071 lines
42 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017 Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RiuRelativePermeabilityPlotPanel.h"
#include "RiaCurveDataTools.h"
#include "RiaDefines.h"
#include "RiaEclipseUnitTools.h"
#include "RiaInterpolationTools.h"
#include "RiaPhaseTools.h"
#include "RiaPlotDefines.h"
#include "RiaResultNames.h"
#include "RigFlowDiagSolverInterface.h"
#include "RiuDockedQwtPlot.h"
#include "RiuGuiTheme.h"
#include "RiuPlotCurveSymbol.h"
#include "RiuQwtPlotTools.h"
#include "RiuQwtSymbol.h"
#include "RiuRelativePermeabilityPlotUpdater.h"
#include "RiuTextDialog.h"
#include "cafAssert.h"
#include "qwt_legend.h"
#include "qwt_picker_machine.h"
#include "qwt_plot.h"
#include "qwt_plot_curve.h"
#include "qwt_plot_marker.h"
#include "qwt_plot_picker.h"
#include "qwt_scale_engine.h"
#include "qwt_symbol.h"
#include "qwt_text.h"
#include <QButtonGroup>
#include <QCheckBox>
#include <QContextMenuEvent>
#include <QGridLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QMenu>
#include <QPushButton>
#include <QVBoxLayout>
#include <algorithm>
#include <cmath>
#include <functional>
//==================================================================================================
//
//
//
//==================================================================================================
class RelPermQwtPlot : public RiuDockedQwtPlot
{
public:
RelPermQwtPlot( QWidget* parent )
: RiuDockedQwtPlot( parent )
{
}
QSize sizeHint() const override { return QSize( 100, 100 ); }
QSize minimumSizeHint() const override { return QSize( 0, 0 ); }
};
//==================================================================================================
//
//
//
//==================================================================================================
class RiuRelPermQwtPicker : public QwtPicker
{
public:
RiuRelPermQwtPicker( QwtPlot* plot, std::function<QString()> textProvider )
: QwtPicker( QwtPicker::NoRubberBand, QwtPicker::AlwaysOn, plot->canvas() )
, m_textProvider( textProvider )
{
setStateMachine( new QwtPickerTrackerMachine );
}
QwtText trackerText( const QPoint& ) const override
{
QwtText text( m_textProvider() );
text.setRenderFlags( Qt::AlignLeft );
return text;
}
private:
std::function<QString()> m_textProvider;
};
//==================================================================================================
///
/// \class RiuRelativePermeabilityPlotPanel
///
///
///
//==================================================================================================
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiuRelativePermeabilityPlotPanel::RiuRelativePermeabilityPlotPanel( QWidget* parent )
: QWidget( parent )
, m_unitSystem( RiaDefines::EclipseUnitSystem::UNITS_UNKNOWN )
, m_swat( HUGE_VAL )
, m_sgas( HUGE_VAL )
, m_plotUpdater( new RiuRelativePermeabilityPlotUpdater( this ) )
, m_qwtPlot( nullptr )
, m_curveSetGroupBox( nullptr )
, m_showDrainageCheckBox( nullptr )
, m_showImbibitionCheckBox( nullptr )
, m_selectedCurvesButtonGroup( nullptr )
, m_groupBox( nullptr )
, m_logarithmicScaleKrAxisCheckBox( nullptr )
, m_showUnscaledCheckBox( nullptr )
, m_showScaledCheckBox( nullptr )
, m_fixedXAxisCheckBox( nullptr )
, m_fixedLeftYAxisCheckBox( nullptr )
, m_trackerPlotMarker( nullptr )
{
m_qwtPlot = new RelPermQwtPlot( this );
m_qwtPlot->setProperty( "qss-class", "RelPermPlot" );
setPlotDefaults( m_qwtPlot );
applyFontSizes( false );
// Initialize picker for curve value tracking
m_qwtPicker = new RiuRelPermQwtPicker( m_qwtPlot, [this]() { return m_trackerLabel; } );
RiuGuiTheme::styleQwtItem( m_qwtPicker );
connect( m_qwtPicker, SIGNAL( activated( bool ) ), this, SLOT( slotPickerActivated( bool ) ) );
connect( m_qwtPicker, SIGNAL( moved( const QPoint& ) ), this, SLOT( slotPickerPointChanged( const QPoint& ) ) );
m_selectedCurvesButtonGroup = new QButtonGroup( this );
m_selectedCurvesButtonGroup->setExclusive( false );
m_selectedCurvesButtonGroup->addButton( new QCheckBox( "KRW" ), RigFlowDiagDefines::RelPermCurve::KRW );
m_selectedCurvesButtonGroup->addButton( new QCheckBox( "KRG" ), RigFlowDiagDefines::RelPermCurve::KRG );
m_selectedCurvesButtonGroup->addButton( new QCheckBox( "KROW" ), RigFlowDiagDefines::RelPermCurve::KROW );
m_selectedCurvesButtonGroup->addButton( new QCheckBox( "KROG" ), RigFlowDiagDefines::RelPermCurve::KROG );
m_selectedCurvesButtonGroup->addButton( new QCheckBox( "PCOW" ), RigFlowDiagDefines::RelPermCurve::PCOW );
m_selectedCurvesButtonGroup->addButton( new QCheckBox( "PCOG" ), RigFlowDiagDefines::RelPermCurve::PCOG );
// Create Curve Set groupbox
m_curveSetGroupBox = new QGroupBox( "Curve Set" );
QHBoxLayout* curveSetLayout = new QHBoxLayout;
m_curveSetGroupBox->setLayout( curveSetLayout );
m_showDrainageCheckBox = new QCheckBox( "Drainage" );
m_showImbibitionCheckBox = new QCheckBox( "Imbibition" );
m_showDrainageCheckBox->setChecked( true );
m_showImbibitionCheckBox->setChecked( false );
curveSetLayout->addWidget( m_showDrainageCheckBox );
curveSetLayout->addWidget( m_showImbibitionCheckBox );
m_groupBox = new QGroupBox( "Curves" );
QGridLayout* groupBoxLayout = new QGridLayout;
m_groupBox->setLayout( groupBoxLayout );
QList<QAbstractButton*> checkButtonList = m_selectedCurvesButtonGroup->buttons();
for ( int i = 0; i < checkButtonList.size(); i++ )
{
checkButtonList[i]->setChecked( true );
groupBoxLayout->addWidget( checkButtonList[i], i / 2, i % 2 );
}
m_logarithmicScaleKrAxisCheckBox = new QCheckBox( "Log Scale Kr Axis" );
m_showUnscaledCheckBox = new QCheckBox( "Show Unscaled" );
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_fixedXAxisCheckBox->setChecked( true );
m_fixedLeftYAxisCheckBox->setChecked( true );
m_showScaledCheckBox->setChecked( true );
QCheckBox* showCurveSelection = new QCheckBox( "Show Curve Selection" );
showCurveSelection->setCheckState( Qt::Unchecked );
connect( showCurveSelection, SIGNAL( stateChanged( int ) ), SLOT( slotShowCurveSelectionWidgets( int ) ) );
QVBoxLayout* leftLayout = new QVBoxLayout;
leftLayout->addWidget( m_curveSetGroupBox );
leftLayout->addWidget( showCurveSelection );
leftLayout->addWidget( m_groupBox );
leftLayout->addWidget( m_logarithmicScaleKrAxisCheckBox );
leftLayout->addWidget( m_showScaledCheckBox );
leftLayout->addWidget( m_showUnscaledCheckBox );
leftLayout->addWidget( m_fixedXAxisCheckBox );
leftLayout->addWidget( m_fixedLeftYAxisCheckBox );
leftLayout->addStretch( 1 );
QHBoxLayout* mainLayout = new QHBoxLayout();
mainLayout->addLayout( leftLayout );
mainLayout->addWidget( m_qwtPlot );
mainLayout->setContentsMargins( 5, 0, 0, 0 );
setLayout( mainLayout );
connect( m_selectedCurvesButtonGroup, SIGNAL( idClicked( int ) ), SLOT( slotButtonInButtonGroupClicked( int ) ) );
connect( m_showDrainageCheckBox, SIGNAL( stateChanged( int ) ), SLOT( slotSomeCheckBoxStateChanged( int ) ) );
connect( m_showImbibitionCheckBox, SIGNAL( stateChanged( int ) ), SLOT( slotSomeCheckBoxStateChanged( int ) ) );
connect( m_logarithmicScaleKrAxisCheckBox, SIGNAL( stateChanged( int ) ), SLOT( slotSomeCheckBoxStateChanged( int ) ) );
connect( m_showUnscaledCheckBox, SIGNAL( stateChanged( int ) ), SLOT( slotSomeCheckBoxStateChanged( int ) ) );
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 ) ) );
slotShowCurveSelectionWidgets( showCurveSelection->checkState() );
plotUiSelectedCurves();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiuRelativePermeabilityPlotPanel::~RiuRelativePermeabilityPlotPanel()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::setPlotDefaults( QwtPlot* plot )
{
RiuQwtPlotTools::setCommonPlotBehaviour( plot );
{
QwtText plotTitle = plot->title();
QFont titleFont = plotTitle.font();
titleFont.setPointSize( 10 );
plotTitle.setFont( titleFont );
plot->setTitle( plotTitle );
}
plot->setAxesCount( QwtAxis::XBottom, 1 );
plot->setAxesCount( QwtAxis::YLeft, 1 );
plot->setAxisMaxMinor( QwtAxis::XBottom, 2 );
plot->setAxisMaxMinor( QwtAxis::YLeft, 3 );
QwtLegend* legend = new QwtLegend( plot );
plot->insertLegend( legend, QwtPlot::BottomLegend );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::setPlotData( RiaDefines::EclipseUnitSystem unitSystem,
const std::vector<RigFlowDiagDefines::RelPermCurve>& relPermCurves,
double swat,
double sgas,
const QString& caseName,
const QString& cellReferenceText,
const std::set<RiaDefines::PhaseType>& availablePhases )
{
// cvf::Trace::show("Set RelPerm plot data");
m_unitSystem = unitSystem;
m_allCurvesArr = relPermCurves;
m_swat = swat;
m_sgas = sgas;
m_caseName = caseName;
m_cellReferenceText = cellReferenceText;
m_availablePhases = availablePhases;
updateCheckboxTexts();
plotUiSelectedCurves();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::enableImbibitionCurveSelection( bool enable )
{
if ( !enable )
{
m_showImbibitionCheckBox->setChecked( false );
m_showImbibitionCheckBox->setDisabled( true );
}
else
{
m_showImbibitionCheckBox->setDisabled( false );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::clearPlot()
{
// cvf::Trace::show("Clear RelPerm plot data");
if ( m_allCurvesArr.empty() && m_cellReferenceText.isEmpty() )
{
return;
}
m_unitSystem = RiaDefines::EclipseUnitSystem::UNITS_UNKNOWN;
m_allCurvesArr.clear();
m_swat = HUGE_VAL;
m_sgas = HUGE_VAL;
m_caseName.clear();
m_cellReferenceText.clear();
plotCurvesInQwt( m_unitSystem,
m_allCurvesArr,
m_swat,
m_sgas,
m_cellReferenceText,
false,
true,
true,
m_qwtPlot,
&m_myPlotMarkers,
false,
false,
m_availablePhases );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiuRelativePermeabilityPlotUpdater* RiuRelativePermeabilityPlotPanel::plotUpdater()
{
return m_plotUpdater.get();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::applyFontSizes( bool replot /*= true*/ )
{
m_qwtPlot->applyFontSizes( replot );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::plotUiSelectedCurves()
{
std::vector<RigFlowDiagDefines::RelPermCurve> selectedCurves = gatherUiSelectedCurves();
const bool useLogScale = m_logarithmicScaleKrAxisCheckBox->isChecked();
const bool fixedXAxis = m_fixedXAxisCheckBox->isChecked();
const bool fixedYAxis = m_fixedLeftYAxisCheckBox->isChecked();
plotCurvesInQwt( m_unitSystem,
selectedCurves,
m_swat,
m_sgas,
m_cellReferenceText,
useLogScale,
fixedXAxis,
fixedYAxis,
m_qwtPlot,
&m_myPlotMarkers,
m_showScaledCheckBox->isChecked(),
m_showUnscaledCheckBox->isChecked(),
m_availablePhases );
}
//--------------------------------------------------------------------------------------------------
/// Add a transparent curve to make tooltip available on given points.
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::addTransparentCurve( QwtPlot* plot,
const std::vector<QPointF>& points,
const std::vector<WhichYAxis>& axes,
bool logScaleLeftAxis )
{
QwtPlotCurve* curveLeftAxis = new QwtPlotCurve();
QwtPlotCurve* curveRightAxis = new QwtPlotCurve();
QVector<QPointF> pointsOnLeftAxis;
QVector<QPointF> pointsOnRightAxis;
// Each point is defined by either left or right axis
CAF_ASSERT( points.size() == axes.size() );
for ( size_t i = 0; i < points.size(); i++ )
{
if ( !RiaCurveDataTools::isValidValue( points[i].y(), logScaleLeftAxis ) ) continue;
if ( axes[i] == LEFT_YAXIS )
{
pointsOnLeftAxis.push_back( points[i] );
}
else
{
pointsOnRightAxis.push_back( points[i] );
}
}
curveLeftAxis->setSamples( pointsOnLeftAxis );
curveRightAxis->setSamples( pointsOnRightAxis );
curveLeftAxis->setYAxis( QwtAxis::YLeft );
curveRightAxis->setYAxis( QwtAxis::YRight );
curveLeftAxis->setStyle( QwtPlotCurve::NoCurve );
curveRightAxis->setStyle( QwtPlotCurve::NoCurve );
curveLeftAxis->setLegendAttribute( QwtPlotCurve::LegendNoAttribute );
curveRightAxis->setLegendAttribute( QwtPlotCurve::LegendNoAttribute );
curveLeftAxis->attach( plot );
curveRightAxis->attach( plot );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::plotCurvesInQwt( RiaDefines::EclipseUnitSystem unitSystem,
const std::vector<RigFlowDiagDefines::RelPermCurve>& curveArr,
double swat,
double sgas,
QString cellReferenceText,
bool logScaleLeftAxis,
bool fixedXAxis,
bool fixedLeftYAxis,
QwtPlot* plot,
std::vector<QwtPlotMarker*>* myPlotMarkers,
bool showScaled,
bool showUnscaled,
const std::set<RiaDefines::PhaseType>& availablePhases )
{
bool skipUnscaledLegends = showScaled && showUnscaled;
plot->detachItems( QwtPlotItem::Rtti_PlotCurve );
// Workaround for detaching only plot markers that we have added
// Needed as long as the curve point tracker is also using plot markers for its marking
// plot->detachItems(QwtPlotItem::Rtti_PlotMarker);
for ( QwtPlotMarker* marker : *myPlotMarkers )
{
marker->detach();
delete marker;
}
myPlotMarkers->clear();
std::vector<QPointF> points;
std::vector<WhichYAxis> axes;
const QColor waterColor = RiuGuiTheme::getColorByVariableName( "curveColorWater" );
const QColor gasColor = RiuGuiTheme::getColorByVariableName( "curveColorGas" );
bool shouldEnableRightYAxis = false;
for ( size_t i = 0; i < curveArr.size(); i++ )
{
const RigFlowDiagDefines::RelPermCurve& curve = curveArr[i];
const auto unscaledCurve = ( curve.epsMode == RigFlowDiagDefines::RelPermCurve::EPS_OFF );
// Which axis should this curve be plotted on
WhichYAxis plotOnWhichYAxis = LEFT_YAXIS;
if ( curve.ident == RigFlowDiagDefines::RelPermCurve::PCOW || curve.ident == RigFlowDiagDefines::RelPermCurve::PCOG )
{
plotOnWhichYAxis = RIGHT_YAXIS;
}
// Determine display name for the curve
std::string displayName = curve.name;
if ( curve.ident == RigFlowDiagDefines::RelPermCurve::PCOG )
{
std::string preferredName;
if ( curve.curveSet == RigFlowDiagDefines::RelPermCurve::IMBIBITION )
{
preferredName += "I";
}
preferredName += RiaPhaseTools::getPreferredPcogName( availablePhases ).toStdString();
displayName = preferredName;
}
QwtPlotCurve* qwtCurve = new QwtPlotCurve( displayName.c_str() );
CAF_ASSERT( curve.saturationVals.size() == curve.yVals.size() );
qwtCurve->setSamples( curve.saturationVals.data(), curve.yVals.data(), static_cast<int>( curve.saturationVals.size() ) );
// Use the display name which may be modified for GAS/WATER cases
qwtCurve->setTitle( displayName.c_str() );
qwtCurve->setStyle( QwtPlotCurve::Lines );
auto penStyle = Qt::SolidLine;
if ( curve.ident == RigFlowDiagDefines::RelPermCurve::PCOW || curve.ident == RigFlowDiagDefines::RelPermCurve::PCOG )
{
penStyle = Qt::DashLine;
}
const QPen curvePen( QBrush(), 1, penStyle );
qwtCurve->setPen( curvePen );
auto* curveSymbol = unscaledCurve ? new RiuQwtSymbol( RiuPlotCurveSymbol::SYMBOL_CROSS )
: new RiuQwtSymbol( RiuPlotCurveSymbol::SYMBOL_ELLIPSE );
curveSymbol->setSize( 6, 6 );
curveSymbol->setBrush( Qt::NoBrush );
qwtCurve->setSymbol( curveSymbol );
qwtCurve->setLegendAttribute( QwtPlotCurve::LegendShowLine, true );
qwtCurve->setLegendAttribute( QwtPlotCurve::LegendShowSymbol, false );
qwtCurve->setLegendAttribute( QwtPlotCurve::LegendShowBrush, true );
const bool showLegend = !( unscaledCurve && skipUnscaledLegends );
qwtCurve->setItemAttribute( QwtPlotItem::Legend, showLegend );
qwtCurve->setRenderHint( QwtPlotItem::RenderAntialiased, true );
if ( plotOnWhichYAxis == RIGHT_YAXIS )
{
qwtCurve->setYAxis( { QwtAxis::YRight, 0 } );
shouldEnableRightYAxis = true;
}
qwtCurve->attach( plot );
RiuGuiTheme::styleQwtItem( qwtCurve );
// Add markers to indicate where SWAT and/or SGAS saturation intersects the respective curves
// Note that if we're using log scale we must guard against non-positive values
if ( swat != HUGE_VAL )
{
if ( curve.ident == RigFlowDiagDefines::RelPermCurve::KRW || curve.ident == RigFlowDiagDefines::RelPermCurve::KROW ||
curve.ident == RigFlowDiagDefines::RelPermCurve::PCOW )
{
addCurveConstSaturationIntersectionMarker( curve, swat, waterColor, plotOnWhichYAxis, plot, myPlotMarkers, &points, &axes );
}
}
if ( sgas != HUGE_VAL )
{
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 );
}
}
}
if ( shouldEnableRightYAxis )
{
plot->setAxesCount( QwtAxis::YRight, 1 );
plot->setAxisVisible( QwtAxis::YRight, true );
}
else
{
plot->setAxesCount( QwtAxis::YRight, 0 );
plot->setAxisVisible( QwtAxis::YRight, false );
}
addTransparentCurve( plot, points, axes, logScaleLeftAxis );
// Add vertical marker lines to indicate cell SWAT and/or SGAS saturations
if ( swat != HUGE_VAL )
{
addVerticalSaturationMarkerLine( swat, RiaResultNames::swat(), waterColor, plot, myPlotMarkers );
}
if ( sgas != HUGE_VAL )
{
addVerticalSaturationMarkerLine( sgas, RiaResultNames::sgas(), gasColor, plot, myPlotMarkers );
}
if ( logScaleLeftAxis )
{
if ( !dynamic_cast<QwtLogScaleEngine*>( plot->axisScaleEngine( QwtAxis::YLeft ) ) )
{
plot->setAxisScaleEngine( QwtAxis::YLeft, new QwtLogScaleEngine );
}
}
else
{
if ( !dynamic_cast<QwtLinearScaleEngine*>( plot->axisScaleEngine( QwtAxis::YLeft ) ) )
{
plot->setAxisScaleEngine( QwtAxis::YLeft, new QwtLinearScaleEngine );
}
}
if ( fixedXAxis )
{
plot->setAxisScale( QwtAxis::XBottom, 0.0, 1.0 );
plot->setAxisAutoScale( QwtAxis::XBottom, false );
}
else
{
plot->setAxisAutoScale( QwtAxis::XBottom, true );
}
if ( fixedLeftYAxis )
{
if ( logScaleLeftAxis )
{
plot->setAxisScale( QwtAxis::YLeft, 1.0e-6, 1.0 );
}
else
{
plot->setAxisScale( QwtAxis::YLeft, 0.0, 1.0 );
}
plot->setAxisAutoScale( QwtAxis::YLeft, false );
}
else
{
plot->setAxisAutoScale( QwtAxis::YLeft, true );
}
if ( showScaled )
{
QwtPlotCurve* curve = getLegendCurve( "Scaled", true /*scaled*/ );
curve->attach( plot );
}
if ( showUnscaled )
{
QwtPlotCurve* curve = getLegendCurve( "Unscaled", false /*scaled*/ );
curve->attach( plot );
}
QString titleStr = "Relative Permeability";
if ( !cellReferenceText.isEmpty() )
{
titleStr += ", " + cellReferenceText;
}
plot->setTitle( titleStr );
plot->setAxisTitle( QwtAxis::XBottom, determineXAxisTitleFromCurveCollection( curveArr ) );
plot->setAxisTitle( QwtAxis::YLeft, "Kr" );
plot->setAxisTitle( QwtAxis::YRight, QString( "Pc [%1]" ).arg( RiaEclipseUnitTools::unitStringPressure( unitSystem ) ) );
plot->replot();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QwtPlotCurve* RiuRelativePermeabilityPlotPanel::getLegendCurve( QString title, bool scaled )
{
QwtPlotCurve* curve = new QwtPlotCurve( title );
curve->setTitle( title );
curve->setStyle( QwtPlotCurve::Lines );
const QPen curvePen( QBrush(), 1, Qt::SolidLine );
curve->setPen( curvePen );
auto* curveSymbol = scaled ? new RiuQwtSymbol( RiuPlotCurveSymbol::SYMBOL_ELLIPSE ) : new RiuQwtSymbol( RiuPlotCurveSymbol::SYMBOL_CROSS );
curveSymbol->setSize( 6, 6 );
curveSymbol->setBrush( QBrush() );
curve->setSymbol( curveSymbol );
curve->setLegendAttribute( QwtPlotCurve::LegendShowLine, true );
curve->setLegendAttribute( QwtPlotCurve::LegendShowSymbol, true );
curve->setLegendAttribute( QwtPlotCurve::LegendShowBrush, false );
curve->setItemAttribute( QwtPlotItem::Legend, true );
return curve;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RiuRelativePermeabilityPlotPanel::determineXAxisTitleFromCurveCollection( const std::vector<RigFlowDiagDefines::RelPermCurve>& curveArr )
{
bool sawWater = false;
bool sawGas = false;
for ( const RigFlowDiagDefines::RelPermCurve& curve : curveArr )
{
if ( curve.isWaterCurve() ) sawWater = true;
if ( curve.isGasCurve() ) sawGas = true;
}
QString title = "";
if ( sawWater && sawGas )
title = "SWAT/SGAS";
else if ( sawWater )
title = "SWAT";
else if ( sawGas )
title = "SGAS";
return title;
}
//--------------------------------------------------------------------------------------------------
/// Add a vertical labeled marker line at the specified saturation value
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::addVerticalSaturationMarkerLine( double saturationValue,
QString label,
QColor color,
QwtPlot* plot,
std::vector<QwtPlotMarker*>* myPlotMarkers )
{
QwtPlotMarker* lineMarker = new QwtPlotMarker;
lineMarker->setXValue( saturationValue );
lineMarker->setLineStyle( QwtPlotMarker::VLine );
lineMarker->setLinePen( QPen( color, 1, Qt::DotLine ) );
lineMarker->setLabel( label );
lineMarker->setLabelAlignment( Qt::AlignTop | Qt::AlignRight );
lineMarker->setLabelOrientation( Qt::Vertical );
lineMarker->attach( plot );
myPlotMarkers->push_back( lineMarker );
}
//--------------------------------------------------------------------------------------------------
/// Add a marker at the intersection of the passed curve and the constant saturation value
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::addCurveConstSaturationIntersectionMarker( const RigFlowDiagDefines::RelPermCurve& curve,
double saturationValue,
QColor markerColor,
WhichYAxis whichYAxis,
QwtPlot* plot,
std::vector<QwtPlotMarker*>* myPlotMarkers,
std::vector<QPointF>* points,
std::vector<WhichYAxis>* axes )
{
const double yVal = RiaInterpolationTools::linear( curve.saturationVals, curve.yVals, saturationValue );
if ( yVal != HUGE_VAL )
{
QwtPlotMarker* pointMarker = new QwtPlotMarker;
pointMarker->setValue( saturationValue, yVal );
QwtSymbol* symbol = new QwtSymbol( QwtSymbol::Ellipse );
symbol->setSize( 13, 13 );
symbol->setPen( QPen( markerColor, 2 ) );
symbol->setBrush( Qt::NoBrush );
pointMarker->setSymbol( symbol );
pointMarker->attach( plot );
if ( whichYAxis == RIGHT_YAXIS )
{
pointMarker->setYAxis( QwtAxis::YRight );
}
myPlotMarkers->push_back( pointMarker );
axes->push_back( whichYAxis );
points->push_back( QPointF( saturationValue, yVal ) );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RigFlowDiagDefines::RelPermCurve> RiuRelativePermeabilityPlotPanel::gatherUiSelectedCurves() const
{
std::vector<RigFlowDiagDefines::RelPermCurve> selectedCurves;
// Determine which curves to actually plot based on selection in GUI
const bool showScaled = m_showScaledCheckBox->isChecked();
const bool showUnscaled = m_showUnscaledCheckBox->isChecked();
const bool showDrainage = m_showDrainageCheckBox->isChecked();
const bool showImbibition = m_showImbibitionCheckBox->isChecked();
for ( size_t i = 0; i < m_allCurvesArr.size(); i++ )
{
const RigFlowDiagDefines::RelPermCurve::Ident curveIdent = m_allCurvesArr[i].ident;
const RigFlowDiagDefines::RelPermCurve::EpsMode curveEpsMode = m_allCurvesArr[i].epsMode;
const RigFlowDiagDefines::RelPermCurve::CurveSet curveSet = m_allCurvesArr[i].curveSet;
// Check if curve type is selected
const bool curveSetSelected = ( curveSet == RigFlowDiagDefines::RelPermCurve::DRAINAGE && showDrainage ) ||
( curveSet == RigFlowDiagDefines::RelPermCurve::IMBIBITION && showImbibition );
if ( curveSetSelected && m_selectedCurvesButtonGroup->button( curveIdent ) &&
m_selectedCurvesButtonGroup->button( curveIdent )->isChecked() )
{
if ( ( ( curveEpsMode == RigFlowDiagDefines::RelPermCurve::EPS_ON ) && showScaled ) ||
( ( curveEpsMode == RigFlowDiagDefines::RelPermCurve::EPS_OFF ) && showUnscaled ) )
{
selectedCurves.push_back( m_allCurvesArr[i] );
}
}
}
return selectedCurves;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RiuRelativePermeabilityPlotPanel::asciiDataForUiSelectedCurves() const
{
std::vector<RigFlowDiagDefines::RelPermCurve> selectedCurves = gatherUiSelectedCurves();
QString outTxt;
// Info header
outTxt += m_caseName + ", " + m_cellReferenceText + "\n";
// Column headers
for ( size_t icurve = 0; icurve < selectedCurves.size(); icurve++ )
{
if ( icurve > 0 ) outTxt += "\t";
const RigFlowDiagDefines::RelPermCurve& curve = selectedCurves[icurve];
if ( curve.isWaterCurve() )
outTxt += "SWAT";
else if ( curve.isGasCurve() )
outTxt += "SGAS";
else
outTxt += "Saturation";
outTxt += "\t";
outTxt += curve.name.c_str();
}
// Table data
size_t sampleIndex = 0;
bool iterationContributedData = true;
while ( iterationContributedData )
{
iterationContributedData = false;
QString lineStr = "\n";
for ( size_t icurve = 0; icurve < selectedCurves.size(); icurve++ )
{
if ( icurve > 0 ) lineStr += "\t";
const RigFlowDiagDefines::RelPermCurve& curve = selectedCurves[icurve];
if ( sampleIndex < curve.saturationVals.size() && sampleIndex < curve.yVals.size() )
{
lineStr += QString::number( curve.saturationVals[sampleIndex], 'g', 6 );
lineStr += "\t";
lineStr += QString::number( curve.yVals[sampleIndex], 'g', 6 );
iterationContributedData = true;
}
else
{
lineStr += "\t";
}
}
if ( iterationContributedData )
{
outTxt += lineStr;
}
sampleIndex++;
}
return outTxt;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::updateCheckboxTexts()
{
// Update PCOG checkbox text to PCGW for GAS/WATER cases
if ( auto button = m_selectedCurvesButtonGroup->button( RigFlowDiagDefines::RelPermCurve::PCOG ) )
{
QString preferredName = RiaPhaseTools::getPreferredPcogName( m_availablePhases );
button->setText( preferredName );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::contextMenuEvent( QContextMenuEvent* event )
{
QMenu menu;
const int curveCount = m_qwtPlot->itemList( QwtPlotItem::Rtti_PlotCurve ).count();
QAction* act = menu.addAction( "Show Plot Data", this, SLOT( slotCurrentPlotDataInTextDialog() ) );
act->setEnabled( curveCount > 0 );
menu.exec( event->globalPos() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::slotCurrentPlotDataInTextDialog()
{
QString outTxt = asciiDataForUiSelectedCurves();
RiuTextDialog* textDialog = new RiuTextDialog( this );
textDialog->setMinimumSize( 400, 600 );
textDialog->setWindowTitle( "Relative Permeability Data" );
textDialog->setText( outTxt );
textDialog->show();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::slotShowCurveSelectionWidgets( int state )
{
bool setVisible = ( state != Qt::CheckState::Unchecked );
m_groupBox->setVisible( setVisible );
m_showUnscaledCheckBox->setVisible( setVisible );
m_showScaledCheckBox->setVisible( setVisible );
m_logarithmicScaleKrAxisCheckBox->setVisible( setVisible );
m_fixedXAxisCheckBox->setVisible( setVisible );
m_fixedLeftYAxisCheckBox->setVisible( setVisible );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::slotButtonInButtonGroupClicked( int )
{
plotUiSelectedCurves();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::slotSomeCheckBoxStateChanged( int )
{
plotUiSelectedCurves();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::showEvent( QShowEvent* event )
{
if ( m_plotUpdater != nullptr ) m_plotUpdater->doDelayedUpdate();
QWidget::showEvent( event );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::slotPickerPointChanged( const QPoint& pt )
{
updateTrackerPlotMarkerAndLabelFromPicker();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::slotPickerActivated( bool on )
{
updateTrackerPlotMarkerAndLabelFromPicker();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiuRelativePermeabilityPlotPanel::updateTrackerPlotMarkerAndLabelFromPicker()
{
bool hasValidSamplePoint = false;
QPointF samplePoint;
QString curveTitle = "";
if ( m_qwtPicker && m_qwtPicker->isActive() )
{
const QPoint trackerPos = m_qwtPicker->trackerPosition();
int pointSampleIdx = -1;
const QwtPlotCurve* closestQwtCurve = closestCurveSample( trackerPos, &pointSampleIdx );
if ( closestQwtCurve && pointSampleIdx >= 0 )
{
samplePoint = closestQwtCurve->sample( pointSampleIdx );
hasValidSamplePoint = true;
curveTitle = closestQwtCurve->title().text();
}
}
m_trackerLabel = "";
bool needsReplot = false;
if ( hasValidSamplePoint )
{
if ( !m_trackerPlotMarker )
{
m_trackerPlotMarker = new QwtPlotMarker;
m_trackerPlotMarker->setTitle( QString( "TrackedPoint" ) );
QwtSymbol* symbol = new QwtSymbol( QwtSymbol::Ellipse );
symbol->setSize( 13, 13 );
symbol->setBrush( Qt::NoBrush );
m_trackerPlotMarker->setSymbol( symbol );
m_trackerPlotMarker->attach( m_qwtPlot );
RiuGuiTheme::styleQwtItem( m_trackerPlotMarker );
needsReplot = true;
}
if ( m_trackerPlotMarker->value() != samplePoint )
{
m_trackerPlotMarker->setValue( samplePoint );
needsReplot = true;
}
m_trackerLabel = QString( "%1: (%2, %3)" ).arg( curveTitle ).arg( samplePoint.x(), 0, 'f', 3 ).arg( samplePoint.y(), 0, 'f', 3 );
}
else
{
if ( m_trackerPlotMarker )
{
m_trackerPlotMarker->detach();
delete m_trackerPlotMarker;
m_trackerPlotMarker = nullptr;
needsReplot = true;
}
}
if ( needsReplot )
{
m_qwtPlot->replot();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const QwtPlotCurve* RiuRelativePermeabilityPlotPanel::closestCurveSample( const QPoint& cursorPosition, int* closestSampleIndex ) const
{
if ( !m_qwtPlot ) return nullptr;
// Get all curves currently attached to the plot
const QwtPlotItemList& plotItems = m_qwtPlot->itemList( QwtPlotItem::Rtti_PlotCurve );
double minDistSquared = std::numeric_limits<double>::max();
const QwtPlotCurve* closestCurve = nullptr;
int closestPtIdx = -1;
for ( auto plotItem : plotItems )
{
const QwtPlotCurve* candidateCurve = dynamic_cast<const QwtPlotCurve*>( plotItem );
if ( !candidateCurve || !candidateCurve->isVisible() ) continue;
for ( size_t ptIdx = 0; ptIdx < candidateCurve->dataSize(); ptIdx++ )
{
QPointF samplePoint = candidateCurve->sample( static_cast<int>( ptIdx ) );
QPoint screenPoint = QPoint( m_qwtPlot->transform( candidateCurve->xAxis(), samplePoint.x() ),
m_qwtPlot->transform( candidateCurve->yAxis(), samplePoint.y() ) );
double distSquared = pow( screenPoint.x() - cursorPosition.x(), 2 ) + pow( screenPoint.y() - cursorPosition.y(), 2 );
if ( distSquared < minDistSquared )
{
minDistSquared = distSquared;
closestCurve = candidateCurve;
closestPtIdx = static_cast<int>( ptIdx );
}
}
}
const double maxAllowedDistanceSquared = 20.0 * 20.0; // 20 pixels
if ( minDistSquared <= maxAllowedDistanceSquared )
{
if ( closestSampleIndex ) *closestSampleIndex = closestPtIdx;
return closestCurve;
}
return nullptr;
}