///////////////////////////////////////////////////////////////////////////////// // // 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 // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RiuPvtPlotPanel.h" #include "RiuDockedQwtPlot.h" #include "RiuPvtPlotUpdater.h" #include "RigFlowDiagSolverInterface.h" #include "cvfAssert.h" //#include "cvfTrace.h" #include "cvfMath.h" #include "qwt_legend.h" #include "qwt_picker_machine.h" #include "qwt_plot.h" #include "qwt_plot_curve.h" #include "qwt_plot_grid.h" #include "qwt_plot_layout.h" #include "qwt_plot_marker.h" #include "qwt_plot_picker.h" #include "qwt_symbol.h" #include #include #include #include #include //================================================================================================== // // // //================================================================================================== class PvtQwtPlot : public RiuDockedQwtPlot { public: PvtQwtPlot( QWidget* parent ) : RiuDockedQwtPlot( parent ) { } QSize sizeHint() const override { return QSize( 100, 100 ); } QSize minimumSizeHint() const override { return QSize( 0, 0 ); } }; //================================================================================================== // // // //================================================================================================== class RiuPvtQwtPicker : public QwtPicker { public: RiuPvtQwtPicker( QwtPlot* plot, RiuPvtTrackerTextProvider* trackerTextProvider ) : QwtPicker( QwtPicker::NoRubberBand, QwtPicker::AlwaysOn, plot->canvas() ) , m_trackerTextProvider( trackerTextProvider ) { setStateMachine( new QwtPickerTrackerMachine ); } QwtText trackerText( const QPoint& ) const override { QwtText text( m_trackerTextProvider->trackerText() ); text.setRenderFlags( Qt::AlignLeft ); return text; } private: const RiuPvtTrackerTextProvider* m_trackerTextProvider; }; //================================================================================================== /// /// \class RiuPvtPlotWidget /// /// /// //================================================================================================== //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RiuPvtPlotWidget::RiuPvtPlotWidget( RiuPvtPlotPanel* parent ) : QWidget( parent ) , m_trackerPlotMarker( nullptr ) { m_qwtPlot = new PvtQwtPlot( this ); setPlotDefaults( m_qwtPlot ); applyFontSizes( false ); QHBoxLayout* layout = new QHBoxLayout(); layout->addWidget( m_qwtPlot ); layout->setSpacing( 0 ); layout->setContentsMargins( 0, 0, 0, 0 ); setLayout( layout ); m_qwtPicker = new RiuPvtQwtPicker( m_qwtPlot, this ); connect( m_qwtPicker, SIGNAL( activated( bool ) ), this, SLOT( slotPickerActivated( bool ) ) ); connect( m_qwtPicker, SIGNAL( moved( const QPoint& ) ), this, SLOT( slotPickerPointChanged( const QPoint& ) ) ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuPvtPlotWidget::setPlotDefaults( QwtPlot* plot ) { // Plot background and frame look QPalette newPalette( plot->palette() ); newPalette.setColor( QPalette::Background, Qt::white ); plot->setPalette( newPalette ); plot->setAutoFillBackground( true ); plot->setCanvasBackground( Qt::white ); QFrame* canvasFrame = dynamic_cast( plot->canvas() ); if ( canvasFrame ) { canvasFrame->setFrameShape( QFrame::NoFrame ); } // Grid { QwtPlotGrid* grid = new QwtPlotGrid; grid->attach( plot ); QPen gridPen( Qt::SolidLine ); gridPen.setColor( Qt::lightGray ); grid->setPen( gridPen ); } // Axis number font { QFont axisFont = plot->axisFont( QwtPlot::xBottom ); axisFont.setPointSize( 8 ); plot->setAxisFont( QwtPlot::xBottom, axisFont ); plot->setAxisFont( QwtPlot::yLeft, axisFont ); } // Axis title font { QwtText axisTitle = plot->axisTitle( QwtPlot::xBottom ); QFont axisTitleFont = axisTitle.font(); axisTitleFont.setPointSize( 8 ); axisTitleFont.setBold( false ); axisTitle.setFont( axisTitleFont ); axisTitle.setRenderFlags( Qt::AlignRight ); plot->setAxisTitle( QwtPlot::xBottom, axisTitle ); plot->setAxisTitle( QwtPlot::yLeft, axisTitle ); } // Title font { QwtText plotTitle = plot->title(); QFont titleFont = plotTitle.font(); titleFont.setPointSize( 12 ); plotTitle.setFont( titleFont ); plot->setTitle( plotTitle ); } plot->setAxisMaxMinor( QwtPlot::xBottom, 2 ); plot->setAxisMaxMinor( QwtPlot::yLeft, 3 ); plot->plotLayout()->setAlignCanvasToScales( true ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuPvtPlotWidget::plotCurves( RiaEclipseUnitTools::UnitSystem unitSystem, const std::vector& curveArr, double pressure, double pointMarkerYValue, QString pointMarkerLabel, QString plotTitle, QString yAxisTitle ) { m_qwtPlot->detachItems( QwtPlotItem::Rtti_PlotCurve ); m_qwtPlot->detachItems( QwtPlotItem::Rtti_PlotMarker ); m_qwtCurveArr.clear(); m_pvtCurveArr.clear(); m_trackerPlotMarker = nullptr; // Construct an auxiliary curve that connects the first point in all the input curves as a visual aid // This should only be shown when the phase being plotted is oil // Will not be added to our array of qwt curves since we do not expect the user to interact with it { std::vector xVals; std::vector yVals; for ( size_t i = 0; i < curveArr.size(); i++ ) { const RigFlowDiagSolverInterface::PvtCurve& curve = curveArr[i]; if ( curve.phase == RigFlowDiagSolverInterface::PvtCurve::OIL && curve.pressureVals.size() > 0 && curve.yVals.size() > 0 ) { xVals.push_back( curve.pressureVals[0] ); yVals.push_back( curve.yVals[0] ); } } if ( xVals.size() > 1 ) { QwtPlotCurve* qwtCurve = new QwtPlotCurve(); qwtCurve->setSamples( xVals.data(), yVals.data(), static_cast( xVals.size() ) ); qwtCurve->setStyle( QwtPlotCurve::Lines ); qwtCurve->setRenderHint( QwtPlotItem::RenderAntialiased, true ); QColor curveClr = Qt::darkGreen; const QPen curvePen( curveClr ); qwtCurve->setPen( curvePen ); qwtCurve->attach( m_qwtPlot ); } } // Add the primary curves for ( size_t i = 0; i < curveArr.size(); i++ ) { const RigFlowDiagSolverInterface::PvtCurve& curve = curveArr[i]; QwtPlotCurve* qwtCurve = new QwtPlotCurve(); CVF_ASSERT( curve.pressureVals.size() == curve.yVals.size() ); qwtCurve->setSamples( curve.pressureVals.data(), curve.yVals.data(), static_cast( curve.pressureVals.size() ) ); qwtCurve->setStyle( QwtPlotCurve::Lines ); QColor curveClr = Qt::magenta; if ( curve.phase == RigFlowDiagSolverInterface::PvtCurve::GAS ) curveClr = QColor( Qt::red ); else if ( curve.phase == RigFlowDiagSolverInterface::PvtCurve::OIL ) curveClr = QColor( Qt::green ); const QPen curvePen( curveClr ); qwtCurve->setPen( curvePen ); qwtCurve->setRenderHint( QwtPlotItem::RenderAntialiased, true ); QwtSymbol* curveSymbol = new QwtSymbol( QwtSymbol::Ellipse ); curveSymbol->setSize( 6, 6 ); curveSymbol->setPen( curvePen ); curveSymbol->setBrush( Qt::NoBrush ); qwtCurve->setSymbol( curveSymbol ); qwtCurve->attach( m_qwtPlot ); m_qwtCurveArr.push_back( qwtCurve ); } m_pvtCurveArr = curveArr; CVF_ASSERT( m_pvtCurveArr.size() == m_qwtCurveArr.size() ); // Add vertical marker line to indicate cell pressure if ( pressure != HUGE_VAL ) { QwtPlotMarker* lineMarker = new QwtPlotMarker; lineMarker->setXValue( pressure ); lineMarker->setLineStyle( QwtPlotMarker::VLine ); lineMarker->setLinePen( QPen( QColor( 128, 128, 255 ), 1, Qt::DashLine ) ); lineMarker->setLabel( QString( "PRESSURE" ) ); lineMarker->setLabelAlignment( Qt::AlignTop | Qt::AlignRight ); lineMarker->setLabelOrientation( Qt::Vertical ); lineMarker->attach( m_qwtPlot ); } // Then point marker if ( pressure != HUGE_VAL && pointMarkerYValue != HUGE_VAL ) { QwtPlotMarker* pointMarker = new QwtPlotMarker; pointMarker->setValue( pressure, pointMarkerYValue ); QColor markerClr( 128, 0, 255 ); QwtSymbol* symbol = new QwtSymbol( QwtSymbol::Ellipse ); symbol->setSize( 13, 13 ); symbol->setPen( QPen( markerClr, 2 ) ); symbol->setBrush( Qt::NoBrush ); pointMarker->setSymbol( symbol ); if ( !pointMarkerLabel.isEmpty() ) { QwtText text( pointMarkerLabel ); text.setRenderFlags( Qt::AlignLeft ); text.setColor( markerClr ); pointMarker->setLabel( text ); pointMarker->setLabelAlignment( Qt::AlignTop | Qt::AlignRight ); } pointMarker->attach( m_qwtPlot ); } m_qwtPlot->setTitle( plotTitle ); m_qwtPlot->setAxisTitle( QwtPlot::xBottom, QString( "Pressure [%1]" ).arg( RiaEclipseUnitTools::unitStringPressure( unitSystem ) ) ); m_qwtPlot->setAxisTitle( QwtPlot::yLeft, yAxisTitle ); updateTrackerPlotMarkerAndLabelFromPicker(); m_qwtPlot->replot(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuPvtPlotWidget::applyFontSizes( bool replot ) { m_qwtPlot->applyFontSizes( replot ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuPvtPlotWidget::updateTrackerPlotMarkerAndLabelFromPicker() { bool hasValidSamplePoint = false; QPointF samplePoint; QString mixRatioText = ""; double mixRat = HUGE_VAL; 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; size_t curveIdx = indexOfQwtCurve( closestQwtCurve ); if ( curveIdx < m_pvtCurveArr.size() ) { const RigFlowDiagSolverInterface::PvtCurve& pvtCurve = m_pvtCurveArr[curveIdx]; if ( static_cast( pointSampleIdx ) < pvtCurve.mixRatVals.size() ) { mixRat = pvtCurve.mixRatVals[pointSampleIdx]; // The text is Rs or Rv depending on phase mixRatioText = ( pvtCurve.phase == RigFlowDiagSolverInterface::PvtCurve::GAS ) ? "Rv" : "Rs"; } } } } m_trackerLabel = ""; bool needsReplot = false; if ( hasValidSamplePoint ) { if ( !m_trackerPlotMarker ) { m_trackerPlotMarker = new QwtPlotMarker; QwtSymbol* symbol = new QwtSymbol( QwtSymbol::Ellipse ); symbol->setSize( 13, 13 ); symbol->setPen( QPen( QColor( 0, 0, 0 ), 2 ) ); symbol->setBrush( Qt::NoBrush ); m_trackerPlotMarker->setSymbol( symbol ); m_trackerPlotMarker->attach( m_qwtPlot ); needsReplot = true; } if ( m_trackerPlotMarker->value() != samplePoint ) { m_trackerPlotMarker->setValue( samplePoint ); needsReplot = true; } m_trackerLabel = QString( "%1 (%2)" ).arg( samplePoint.y() ).arg( samplePoint.x() ); if ( mixRat != HUGE_VAL ) { m_trackerLabel += QString( "\n%1 = %2" ).arg( mixRatioText ).arg( mixRat ); } } else { if ( m_trackerPlotMarker ) { m_trackerPlotMarker->detach(); delete m_trackerPlotMarker; m_trackerPlotMarker = nullptr; needsReplot = true; } } if ( needsReplot ) { m_qwtPlot->replot(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const QwtPlotCurve* RiuPvtPlotWidget::closestCurveSample( const QPoint& cursorPosition, int* closestSampleIndex ) const { // Construct a set containing the relevant qwt curves to consider // These are the curves that have a corresponding Pvt source curve std::set relevantQwtCurvesSet( m_qwtCurveArr.begin(), m_qwtCurveArr.end() ); if ( closestSampleIndex ) *closestSampleIndex = -1; const QwtPlotCurve* closestCurve = nullptr; double distMin = HUGE_VAL; int closestPointSampleIndex = -1; const QwtPlotItemList& itemList = m_qwtPlot->itemList(); for ( QwtPlotItemIterator it = itemList.begin(); it != itemList.end(); it++ ) { if ( ( *it )->rtti() == QwtPlotItem::Rtti_PlotCurve ) { const QwtPlotCurve* curve = static_cast( *it ); if ( relevantQwtCurvesSet.find( curve ) != relevantQwtCurvesSet.end() ) { double dist = HUGE_VAL; int candidateSampleIndex = curve->closestPoint( cursorPosition, &dist ); if ( dist < distMin ) { closestCurve = curve; closestPointSampleIndex = candidateSampleIndex; distMin = dist; } } } } if ( closestCurve && closestPointSampleIndex >= 0 && distMin < 50 ) { if ( closestSampleIndex ) *closestSampleIndex = closestPointSampleIndex; return closestCurve; } else { return nullptr; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- size_t RiuPvtPlotWidget::indexOfQwtCurve( const QwtPlotCurve* qwtCurve ) const { for ( size_t i = 0; i < m_qwtCurveArr.size(); i++ ) { if ( m_qwtCurveArr[i] == qwtCurve ) { return i; } } return cvf::UNDEFINED_SIZE_T; } //-------------------------------------------------------------------------------------------------- /// Implements the RiuPvtTrackerTextProvider interface //-------------------------------------------------------------------------------------------------- QString RiuPvtPlotWidget::trackerText() const { return m_trackerLabel; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuPvtPlotWidget::slotPickerPointChanged( const QPoint& pt ) { updateTrackerPlotMarkerAndLabelFromPicker(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuPvtPlotWidget::slotPickerActivated( bool on ) { updateTrackerPlotMarkerAndLabelFromPicker(); } //================================================================================================== /// /// \class RiuPvtPlotPanel /// /// /// //================================================================================================== //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RiuPvtPlotPanel::RiuPvtPlotPanel( QDockWidget* parent ) : QWidget( parent ) , m_unitSystem( RiaEclipseUnitTools::UNITS_UNKNOWN ) , m_plotUpdater( new RiuPvtPlotUpdater( this ) ) { m_phaseComboBox = new QComboBox( this ); m_phaseComboBox->setEditable( false ); m_phaseComboBox->addItem( "Oil", QVariant( RigFlowDiagSolverInterface::PvtCurve::OIL ) ); m_phaseComboBox->addItem( "Gas", QVariant( RigFlowDiagSolverInterface::PvtCurve::GAS ) ); m_titleLabel = new QLabel( "", this ); m_titleLabel->setAlignment( Qt::AlignHCenter ); QFont font = m_titleLabel->font(); font.setPointSize( 10 ); font.setBold( true ); m_titleLabel->setFont( font ); QHBoxLayout* topLayout = new QHBoxLayout(); topLayout->addWidget( new QLabel( "Phase:" ) ); topLayout->addWidget( m_phaseComboBox ); topLayout->addWidget( m_titleLabel, 1 ); topLayout->setContentsMargins( 5, 5, 0, 0 ); m_fvfPlot = new RiuPvtPlotWidget( this ); m_viscosityPlot = new RiuPvtPlotWidget( this ); QHBoxLayout* plotLayout = new QHBoxLayout(); plotLayout->addWidget( m_fvfPlot ); plotLayout->addWidget( m_viscosityPlot ); plotLayout->setSpacing( 0 ); plotLayout->setContentsMargins( 0, 0, 0, 0 ); QVBoxLayout* mainLayout = new QVBoxLayout(); mainLayout->addLayout( topLayout ); mainLayout->addLayout( plotLayout ); mainLayout->setContentsMargins( 0, 0, 0, 0 ); setLayout( mainLayout ); connect( m_phaseComboBox, SIGNAL( currentIndexChanged( int ) ), SLOT( slotPhaseComboCurrentIndexChanged( int ) ) ); plotUiSelectedCurves(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RiuPvtPlotPanel::~RiuPvtPlotPanel() {} //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuPvtPlotPanel::setPlotData( RiaEclipseUnitTools::UnitSystem unitSystem, const std::vector& fvfCurveArr, const std::vector& viscosityCurveArr, FvfDynProps fvfDynProps, ViscosityDynProps viscosityDynProps, CellValues cellValues, QString cellReferenceText ) { // cvf::Trace::show("RiuPvtPlotPanel::setPlotData()"); m_unitSystem = unitSystem; m_allFvfCurvesArr = fvfCurveArr; m_allViscosityCurvesArr = viscosityCurveArr; m_fvfDynProps = fvfDynProps; m_viscosityDynProps = viscosityDynProps; m_cellValues = cellValues; m_cellReferenceText = cellReferenceText; plotUiSelectedCurves(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuPvtPlotPanel::clearPlot() { // cvf::Trace::show("RiuPvtPlotPanel::clearPlot()"); if ( m_allFvfCurvesArr.empty() && m_allViscosityCurvesArr.empty() && m_cellReferenceText.isEmpty() ) { return; } m_unitSystem = RiaEclipseUnitTools::UNITS_UNKNOWN; m_allFvfCurvesArr.clear(); m_allViscosityCurvesArr.clear(); m_fvfDynProps = FvfDynProps(); m_viscosityDynProps = ViscosityDynProps(); m_cellValues = CellValues(); m_cellReferenceText.clear(); plotUiSelectedCurves(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RiuPvtPlotUpdater* RiuPvtPlotPanel::plotUpdater() { return m_plotUpdater.get(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuPvtPlotPanel::applyFontSizes( bool replot ) { if ( m_fvfPlot ) m_fvfPlot->applyFontSizes( replot ); if ( m_viscosityPlot ) m_viscosityPlot->applyFontSizes( replot ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuPvtPlotPanel::plotUiSelectedCurves() { // Determine which curves (phase) to actually plot based on selection in GUI const int currComboIdx = m_phaseComboBox->currentIndex(); const RigFlowDiagSolverInterface::PvtCurve::Phase phaseToPlot = static_cast( m_phaseComboBox->itemData( currComboIdx ).toInt() ); QString phaseString = ""; if ( phaseToPlot == RigFlowDiagSolverInterface::PvtCurve::GAS ) { phaseString = "Gas "; } else if ( phaseToPlot == RigFlowDiagSolverInterface::PvtCurve::OIL ) { phaseString = "Oil "; } // FVF plot { RigFlowDiagSolverInterface::PvtCurve::Ident curveIdentToPlot = RigFlowDiagSolverInterface::PvtCurve::Unknown; double pointMarkerFvfValue = HUGE_VAL; QString pointMarkerLabel = ""; if ( phaseToPlot == RigFlowDiagSolverInterface::PvtCurve::GAS ) { curveIdentToPlot = RigFlowDiagSolverInterface::PvtCurve::Bg; pointMarkerFvfValue = m_fvfDynProps.bg; pointMarkerLabel = QString( "%1 (%2)" ).arg( pointMarkerFvfValue ).arg( m_cellValues.pressure ); if ( m_cellValues.rv != HUGE_VAL ) { pointMarkerLabel += QString( "\nRv = %1" ).arg( m_cellValues.rv ); } } else if ( phaseToPlot == RigFlowDiagSolverInterface::PvtCurve::OIL ) { curveIdentToPlot = RigFlowDiagSolverInterface::PvtCurve::Bo; pointMarkerFvfValue = m_fvfDynProps.bo; pointMarkerLabel = QString( "%1 (%2)" ).arg( pointMarkerFvfValue ).arg( m_cellValues.pressure ); if ( m_cellValues.rs != HUGE_VAL ) { pointMarkerLabel += QString( "\nRs = %1" ).arg( m_cellValues.rs ); } } std::vector selectedFvfCurves; for ( RigFlowDiagSolverInterface::PvtCurve curve : m_allFvfCurvesArr ) { if ( curve.ident == curveIdentToPlot ) { selectedFvfCurves.push_back( curve ); } } const QString plotTitle = QString( "%1 Formation Volume Factor" ).arg( phaseString ); const QString yAxisTitle = QString( "%1 Formation Volume Factor [%2]" ) .arg( phaseString ) .arg( unitLabelFromCurveIdent( m_unitSystem, curveIdentToPlot ) ); m_fvfPlot->plotCurves( m_unitSystem, selectedFvfCurves, m_cellValues.pressure, pointMarkerFvfValue, pointMarkerLabel, plotTitle, yAxisTitle ); } // Viscosity plot { RigFlowDiagSolverInterface::PvtCurve::Ident curveIdentToPlot = RigFlowDiagSolverInterface::PvtCurve::Unknown; double pointMarkerViscosityValue = HUGE_VAL; QString pointMarkerLabel = ""; if ( phaseToPlot == RigFlowDiagSolverInterface::PvtCurve::GAS ) { curveIdentToPlot = RigFlowDiagSolverInterface::PvtCurve::Visc_g; pointMarkerViscosityValue = m_viscosityDynProps.mu_g; pointMarkerLabel = QString( "%1 (%2)" ).arg( pointMarkerViscosityValue ).arg( m_cellValues.pressure ); if ( m_cellValues.rv != HUGE_VAL ) { pointMarkerLabel += QString( "\nRv = %1" ).arg( m_cellValues.rv ); } } else if ( phaseToPlot == RigFlowDiagSolverInterface::PvtCurve::OIL ) { curveIdentToPlot = RigFlowDiagSolverInterface::PvtCurve::Visc_o; pointMarkerViscosityValue = m_viscosityDynProps.mu_o; pointMarkerLabel = QString( "%1 (%2)" ).arg( pointMarkerViscosityValue ).arg( m_cellValues.pressure ); if ( m_cellValues.rs != HUGE_VAL ) { pointMarkerLabel += QString( "\nRs = %1" ).arg( m_cellValues.rs ); } } std::vector selectedViscosityCurves; for ( RigFlowDiagSolverInterface::PvtCurve curve : m_allViscosityCurvesArr ) { if ( curve.ident == curveIdentToPlot ) { selectedViscosityCurves.push_back( curve ); } } const QString plotTitle = QString( "%1 Viscosity" ).arg( phaseString ); const QString yAxisTitle = QString( "%1 Viscosity [%2]" ) .arg( phaseString ) .arg( unitLabelFromCurveIdent( m_unitSystem, curveIdentToPlot ) ); m_viscosityPlot->plotCurves( m_unitSystem, selectedViscosityCurves, m_cellValues.pressure, pointMarkerViscosityValue, pointMarkerLabel, plotTitle, yAxisTitle ); } // Update the label on top in our panel QString titleStr = "PVT"; if ( !m_cellReferenceText.isEmpty() ) { titleStr += ", " + m_cellReferenceText; } m_titleLabel->setText( titleStr ); } //-------------------------------------------------------------------------------------------------- /// Static helper to get unit labels //-------------------------------------------------------------------------------------------------- QString RiuPvtPlotPanel::unitLabelFromCurveIdent( RiaEclipseUnitTools::UnitSystem unitSystem, RigFlowDiagSolverInterface::PvtCurve::Ident curveIdent ) { if ( curveIdent == RigFlowDiagSolverInterface::PvtCurve::Bo ) { switch ( unitSystem ) { case RiaEclipseUnitTools::UNITS_METRIC: return "rm3/sm3"; case RiaEclipseUnitTools::UNITS_FIELD: return "rb/stb"; case RiaEclipseUnitTools::UNITS_LAB: return "rcc/scc"; default: return ""; } } else if ( curveIdent == RigFlowDiagSolverInterface::PvtCurve::Bg ) { switch ( unitSystem ) { case RiaEclipseUnitTools::UNITS_METRIC: return "rm3/sm3"; case RiaEclipseUnitTools::UNITS_FIELD: return "rb/Mscf"; case RiaEclipseUnitTools::UNITS_LAB: return "rcc/scc"; default: return ""; } } else if ( curveIdent == RigFlowDiagSolverInterface::PvtCurve::Visc_o || curveIdent == RigFlowDiagSolverInterface::PvtCurve::Visc_g ) { switch ( unitSystem ) { case RiaEclipseUnitTools::UNITS_METRIC: return "cP"; case RiaEclipseUnitTools::UNITS_FIELD: return "cP"; case RiaEclipseUnitTools::UNITS_LAB: return "cP"; default: return ""; } } return ""; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RiuPvtPlotPanel::slotPhaseComboCurrentIndexChanged( int ) { plotUiSelectedCurves(); }