Add support for multiple curve sets in one VFP plot

- support selection of multiple values for multiple producer variables
- use one color for curves in a curve set representing a VFP curve collection
- use symbols to indicate individual family values for curves
- show all required values to identify curves as curve legend text and curve mouse hover text
- make sure all available settings of axis property object is applied to the plot axis
- support display of all curve data using "Show Plot Data"
This commit is contained in:
Magne Sjaastad 2024-06-12 07:52:37 +02:00
parent 13532b0fe4
commit fe63231db9
12 changed files with 725 additions and 264 deletions

View File

@ -37,6 +37,7 @@
#include "RimWellLogPlot.h"
#include "RimWellLogTrack.h"
#include "VerticalFlowPerformance/RimCustomVfpPlot.h"
#include "VerticalFlowPerformance/RimVfpPlot.h"
#include "RiuPlotMainWindow.h"
@ -193,7 +194,7 @@ bool RicShowPlotDataFeature::isCommandEnabled() const
for ( auto plot : selection )
{
if ( dynamic_cast<RimSummaryPlot*>( plot ) || dynamic_cast<RimWellLogPlot*>( plot ) || dynamic_cast<RimWellLogTrack*>( plot ) ||
dynamic_cast<RimGridCrossPlot*>( plot ) || dynamic_cast<RimVfpPlot*>( plot ) ||
dynamic_cast<RimGridCrossPlot*>( plot ) || dynamic_cast<RimVfpPlot*>( plot ) || dynamic_cast<RimCustomVfpPlot*>( plot ) ||
dynamic_cast<RimWellAllocationOverTimePlot*>( plot ) || dynamic_cast<RimAnalysisPlot*>( plot ) ||
dynamic_cast<RimCorrelationMatrixPlot*>( plot ) || dynamic_cast<RimAbstractCorrelationPlot*>( plot ) ||
dynamic_cast<RimCorrelationReportPlot*>( plot ) )

View File

@ -107,6 +107,20 @@ RimPlotAxisProperties::RimPlotAxisProperties()
updateOptionSensitivity();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPlotAxisProperties::configureForBasicUse()
{
setEnableTitleTextSettings( false );
m_isLogarithmicScaleEnabled.uiCapability()->setUiHidden( true );
m_isAxisInverted.uiCapability()->setUiHidden( true );
m_showNumbers.uiCapability()->setUiHidden( true );
m_majorTickmarkCount.uiCapability()->setUiHidden( true );
m_plotAxis.uiCapability()->setUiHidden( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -64,6 +64,8 @@ public:
public:
RimPlotAxisProperties();
void configureForBasicUse();
void setAlwaysRequired( bool enable );
void setEnableTitleTextSettings( bool enable );

View File

@ -29,73 +29,16 @@
#include "RimSummaryCase.h"
#include "RimSummaryCaseCollection.h"
#include "RimSummaryCurve.h"
#include "Tools/RimPlotAxisTools.h"
#include "RiuQtChartsPlotWidget.h"
#include "RiuQwtPlotTools.h"
#include "RiuSummaryQuantityNameInfoProvider.h"
#include "RiuSummaryQwtPlot.h"
#include "qwt_date_scale_engine.h"
#include "qwt_plot.h"
#include "qwt_plot_curve.h"
#include "qwt_scale_draw.h"
#include "qwt_text.h"
#include <cmath>
#include <set>
#include <string>
//--------------------------------------------------------------------------------------------------
// e format as [-]9.9e[+|-]999
// E format as[-]9.9E[+| -]999
// f format as[-]9.9
// g use e or f format, whichever is the most concise
// G use E or f format, whichever is the most concise
//--------------------------------------------------------------------------------------------------
class SummaryScaleDraw : public QwtScaleDraw
{
public:
SummaryScaleDraw( double scaleFactor,
int numberOfDecimals,
RimPlotAxisProperties::NumberFormatType numberFormat = RimPlotAxisProperties::NUMBER_FORMAT_AUTO )
{
m_scaleFactor = scaleFactor;
m_numberOfDecimals = numberOfDecimals;
m_numberFormat = numberFormat;
}
QwtText label( double value ) const override
{
if ( qFuzzyCompare( scaledValue( value ) + 1.0, 1.0 ) ) value = 0.0;
return QString::number( scaledValue( value ), numberFormat(), m_numberOfDecimals );
}
private:
char numberFormat() const
{
switch ( m_numberFormat )
{
case RimPlotAxisProperties::NUMBER_FORMAT_AUTO:
return 'g';
case RimPlotAxisProperties::NUMBER_FORMAT_DECIMAL:
return 'f';
case RimPlotAxisProperties::NUMBER_FORMAT_SCIENTIFIC:
return 'e';
default:
return 'g';
}
}
double scaledValue( double value ) const { return value / m_scaleFactor; }
private:
double m_scaleFactor;
int m_numberOfDecimals;
RimPlotAxisProperties::NumberFormatType m_numberFormat;
};
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -139,24 +82,7 @@ void RimSummaryPlotAxisFormatter::applyAxisPropertiesToPlot( RiuPlotWidget* plot
plotWidget->setAxisTitleEnabled( axis, true );
}
auto qwtPlotWidget = dynamic_cast<RiuQwtPlotWidget*>( plotWidget );
if ( qwtPlotWidget )
{
auto qwtAxisId = qwtPlotWidget->toQwtPlotAxis( axis );
if ( m_axisProperties->numberFormat() == RimPlotAxisProperties::NUMBER_FORMAT_AUTO && m_axisProperties->scaleFactor() == 1.0 )
{
// Default to Qwt's own scale draw to avoid changing too much for default values
qwtPlotWidget->qwtPlot()->setAxisScaleDraw( qwtAxisId, new QwtScaleDraw );
}
else
{
qwtPlotWidget->qwtPlot()->setAxisScaleDraw( qwtAxisId,
new SummaryScaleDraw( m_axisProperties->scaleFactor(),
m_axisProperties->decimalCount(),
m_axisProperties->numberFormat() ) );
}
}
RimPlotAxisTools::applyAxisScaleDraw( plotWidget, axis, m_axisProperties );
#ifdef USE_QTCHARTS
auto qtChartsPlotWidget = dynamic_cast<RiuQtChartsPlotWidget*>( plotWidget );
@ -307,13 +233,7 @@ QString RimSummaryPlotAxisFormatter::autoAxisTitle() const
}
QString assembledYAxisText;
QString scaleFactorText = "";
if ( m_axisProperties->scaleFactor() != 1.0 )
{
int exponent = std::log10( m_axisProperties->scaleFactor() );
scaleFactorText = QString( " x 10<sup>%1</sup> " ).arg( QString::number( exponent ) );
}
QString scaleFactorText = RimPlotAxisTools::scaleFactorText( m_axisProperties );
for ( const auto& unitIt : unitToQuantityNameMap )
{

View File

@ -17,19 +17,80 @@
/////////////////////////////////////////////////////////////////////////////////
#include "RimPlotAxisTools.h"
#include "RimPlotAxisLogRangeCalculator.h"
#include "RimPlotAxisProperties.h"
#include "RimPlotCurve.h"
#include "RimSummaryPlotAxisFormatter.h"
#include "RiuPlotAxis.h"
#include "RiuPlotWidget.h"
#include "RiuQwtPlotWidget.h"
#include "qwt_plot.h"
#include "qwt_scale_draw.h"
#include "qwt_text.h"
#include <cmath>
namespace RimPlotAxisTools
{
//--------------------------------------------------------------------------------------------------
// e format as [-]9.9e[+|-]999
// E format as[-]9.9E[+| -]999
// f format as[-]9.9
// g use e or f format, whichever is the most concise
// G use E or f format, whichever is the most concise
//--------------------------------------------------------------------------------------------------
class SummaryScaleDraw : public QwtScaleDraw
{
public:
SummaryScaleDraw( double scaleFactor,
int numberOfDecimals,
RimPlotAxisProperties::NumberFormatType numberFormat = RimPlotAxisProperties::NUMBER_FORMAT_AUTO )
{
m_scaleFactor = scaleFactor;
m_numberOfDecimals = numberOfDecimals;
m_numberFormat = numberFormat;
}
QwtText label( double value ) const override
{
if ( qFuzzyCompare( scaledValue( value ) + 1.0, 1.0 ) ) value = 0.0;
return QString::number( scaledValue( value ), numberFormat(), m_numberOfDecimals );
}
private:
char numberFormat() const
{
switch ( m_numberFormat )
{
case RimPlotAxisProperties::NUMBER_FORMAT_AUTO:
return 'g';
case RimPlotAxisProperties::NUMBER_FORMAT_DECIMAL:
return 'f';
case RimPlotAxisProperties::NUMBER_FORMAT_SCIENTIFIC:
return 'e';
default:
return 'g';
}
}
double scaledValue( double value ) const { return value / m_scaleFactor; }
private:
double m_scaleFactor;
int m_numberOfDecimals;
RimPlotAxisProperties::NumberFormatType m_numberFormat;
};
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPlotAxisTools::updateVisibleRangesFromPlotWidget( RimPlotAxisProperties* axisProperties,
RiuPlotAxis plotAxis,
const RiuPlotWidget* const plotWidget )
void updateVisibleRangesFromPlotWidget( RimPlotAxisProperties* axisProperties, RiuPlotAxis plotAxis, const RiuPlotWidget* const plotWidget )
{
if ( !plotWidget || !axisProperties ) return;
@ -44,11 +105,11 @@ void RimPlotAxisTools::updateVisibleRangesFromPlotWidget( RimPlotAxisProperties*
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimPlotAxisTools::updatePlotWidgetFromAxisProperties( RiuPlotWidget* plotWidget,
RiuPlotAxis axis,
const RimPlotAxisProperties* const axisProperties,
const QString& axisTitle,
const std::vector<const RimPlotCurve*>& plotCurves )
void updatePlotWidgetFromAxisProperties( RiuPlotWidget* plotWidget,
RiuPlotAxis axis,
const RimPlotAxisProperties* const axisProperties,
const QString& axisTitle,
const std::vector<const RimPlotCurve*>& plotCurves )
{
if ( !plotWidget || !axisProperties ) return;
@ -64,10 +125,12 @@ void RimPlotAxisTools::updatePlotWidgetFromAxisProperties( RiuPlotWidget*
plotWidget->setAxisFontsAndAlignment( axis, axisProperties->titleFontSize(), axisProperties->valuesFontSize(), false, alignment );
if ( !axisTitle.isEmpty() )
{
plotWidget->setAxisTitleText( axis, axisTitle );
plotWidget->setAxisTitleText( axis, axisTitle + RimPlotAxisTools::scaleFactorText( axisProperties ) );
}
plotWidget->setAxisTitleEnabled( axis, true );
applyAxisScaleDraw( plotWidget, axis, axisProperties );
if ( axisProperties->isLogarithmicScaleEnabled() )
{
bool isLogScale = plotWidget->axisScaleType( axis ) == RiuPlotWidget::AxisScaleType::LOGARITHMIC;
@ -123,3 +186,43 @@ void RimPlotAxisTools::updatePlotWidgetFromAxisProperties( RiuPlotWidget*
plotWidget->enableAxis( axis, false );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void applyAxisScaleDraw( RiuPlotWidget* plotWidget, RiuPlotAxis axis, const RimPlotAxisProperties* const axisProperties )
{
if ( auto qwtPlotWidget = dynamic_cast<RiuQwtPlotWidget*>( plotWidget ) )
{
auto qwtAxisId = qwtPlotWidget->toQwtPlotAxis( axis );
if ( axisProperties->numberFormat() == RimPlotAxisProperties::NUMBER_FORMAT_AUTO && axisProperties->scaleFactor() == 1.0 )
{
// Default to Qwt's own scale draw to avoid changing too much for default values
qwtPlotWidget->qwtPlot()->setAxisScaleDraw( qwtAxisId, new QwtScaleDraw );
}
else
{
qwtPlotWidget->qwtPlot()->setAxisScaleDraw( qwtAxisId,
new SummaryScaleDraw( axisProperties->scaleFactor(),
axisProperties->decimalCount(),
axisProperties->numberFormat() ) );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString scaleFactorText( const RimPlotAxisProperties* const axisProperties )
{
if ( axisProperties->scaleFactor() != 1.0 )
{
int exponent = std::log10( axisProperties->scaleFactor() );
return QString( " x 10<sup>%1</sup> " ).arg( QString::number( exponent ) );
}
return {};
}
} // namespace RimPlotAxisTools

View File

@ -36,4 +36,7 @@ void updatePlotWidgetFromAxisProperties( RiuPlotWidget*
const QString& axisTitle,
const std::vector<const RimPlotCurve*>& plotCurves );
void applyAxisScaleDraw( RiuPlotWidget* plotWidget, RiuPlotAxis axis, const RimPlotAxisProperties* const axisProperties );
QString scaleFactorText( const RimPlotAxisProperties* const axisProperties );
}; // namespace RimPlotAxisTools

View File

@ -21,6 +21,9 @@
#include "RiaColorTables.h"
#include "RiaColorTools.h"
#include "RiaEclipseUnitTools.h"
#include "RiaPreferences.h"
#include "RifCsvDataTableFormatter.h"
#include "RigVfpTables.h"
@ -71,7 +74,7 @@ RimCustomVfpPlot::RimCustomVfpPlot()
CAF_PDM_InitFieldNoDefault( &m_additionalDataSources, "AdditionalDataSources", "Additional Data Sources" );
m_additionalDataSources.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
CAF_PDM_InitFieldNoDefault( &m_curveOptionFiltering, "CurveOptionFiltering", "Curve Option Filtering" );
CAF_PDM_InitFieldNoDefault( &m_curveValueOptions, "CurveValueOptions", "Curve Value Options" );
CAF_PDM_InitFieldNoDefault( &m_curveMatchingType, "CurveMatchingType", "Curve Matching Type" );
caf::AppEnum<RimVfpDefines::TableType> defaultTableType = RimVfpDefines::TableType::INJECTION;
@ -103,33 +106,35 @@ RimCustomVfpPlot::RimCustomVfpPlot()
caf::AppEnum<RimVfpDefines::ProductionVariableType> defaultFamilyVariable = RimVfpDefines::ProductionVariableType::THP;
CAF_PDM_InitField( &m_familyVariable, "FamilyVariable", defaultFamilyVariable, "Family Variable" );
CAF_PDM_InitField( &m_flowRateIdx, "LiquidFlowRateIdx", { 0 }, "Flow Rate" );
m_flowRateIdx.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() );
CAF_PDM_InitFieldNoDefault( &m_flowRate, "LiquidFlowRate", "Flow Rate" );
m_flowRate.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
CAF_PDM_InitField( &m_thpIdx, "THPIdx", { 0 }, "THP" );
m_thpIdx.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() );
CAF_PDM_InitFieldNoDefault( &m_thp, "THP", "THP" );
m_thp.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
CAF_PDM_InitField( &m_articifialLiftQuantityIdx, "ArtificialLiftQuantityIdx", { 0 }, "Artificial Lift Quantity" );
m_articifialLiftQuantityIdx.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() );
CAF_PDM_InitFieldNoDefault( &m_artificialLiftQuantity, "ArtificialLiftQuantity", "Artificial Lift Quantity" );
m_artificialLiftQuantity.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
CAF_PDM_InitField( &m_waterCutIdx, "WaterCutIdx", { 0 }, "Water Cut" );
m_waterCutIdx.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() );
CAF_PDM_InitFieldNoDefault( &m_waterCut, "WaterCut", "Water Cut" );
m_waterCut.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
CAF_PDM_InitField( &m_gasLiquidRatioIdx, "GasLiquidRatioIdx", { 0 }, "Gas Liquid Ratio" );
m_gasLiquidRatioIdx.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() );
CAF_PDM_InitField( &m_familyValues, "FamilyValues", { 0 }, "Family Values" );
m_familyValues.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
CAF_PDM_InitFieldNoDefault( &m_gasLiquidRatio, "GasLiquidRatio", "Gas Liquid Ratio" );
m_gasLiquidRatio.uiCapability()->setUiEditorTypeName( caf::PdmUiTreeSelectionEditor::uiEditorTypeName() );
CAF_PDM_InitFieldNoDefault( &m_xAxisProperties, "xAxisProperties", "X Axis" );
m_xAxisProperties = new RimPlotAxisProperties;
m_xAxisProperties->setNameAndAxis( "X-Axis", "X-Axis", RiaDefines::PlotAxis::PLOT_AXIS_BOTTOM );
m_xAxisProperties->setEnableTitleTextSettings( false );
m_xAxisProperties->configureForBasicUse();
CAF_PDM_InitFieldNoDefault( &m_yAxisProperties, "yAxisProperties", "Y Axis" );
m_yAxisProperties = new RimPlotAxisProperties;
m_yAxisProperties->setNameAndAxis( "Y-Axis", "Y-Axis", RiaDefines::PlotAxis::PLOT_AXIS_LEFT );
m_yAxisProperties->setEnableTitleTextSettings( false );
m_yAxisProperties->configureForBasicUse();
CAF_PDM_InitField( &m_curveThickness, "CurveThickness", 2, "Line Thickness" );
m_curveThickness.uiCapability()->setUiEditorTypeName( caf::PdmUiComboBoxEditor::uiEditorTypeName() );
CAF_PDM_InitField( &m_curveSymbolSize, "CurveSymbolSize", 10, "Symbol Size" );
connectAxisSignals( m_xAxisProperties() );
connectAxisSignals( m_yAxisProperties() );
@ -184,9 +189,29 @@ void RimCustomVfpPlot::initializeObject()
auto table = vfpTables->getTableInitialData( tableNumber );
initializeFromInitData( table );
}
auto values = vfpTables->getProductionTableData( m_tableNumber(), m_familyVariable() );
m_familyValues = values;
//--------------------------------------------------------------------------------------------------
///
void RimCustomVfpPlot::initializeSelection()
{
std::map<RimVfpDefines::ProductionVariableType, caf::PdmField<std::vector<double>>*> typeAndField =
{ { RimVfpDefines::ProductionVariableType::FLOW_RATE, &m_flowRate },
{ RimVfpDefines::ProductionVariableType::THP, &m_thp },
{ RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY, &m_artificialLiftQuantity },
{ RimVfpDefines::ProductionVariableType::WATER_CUT, &m_waterCut },
{ RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO, &m_gasLiquidRatio } };
for ( const auto& [variableType, field] : typeAndField )
{
auto values = availableValues( variableType );
if ( m_familyVariable() == variableType )
field->v() = values;
else if ( !values.empty() )
field->v() = { values.front() };
else
field->v() = {};
}
}
//--------------------------------------------------------------------------------------------------
@ -228,9 +253,8 @@ void RimCustomVfpPlot::updateAxes()
{
if ( !m_plotWidget ) return;
QString title;
RimPlotAxisTools::updatePlotWidgetFromAxisProperties( m_plotWidget, RiuPlotAxis::defaultBottom(), m_xAxisProperties(), title, {} );
RimPlotAxisTools::updatePlotWidgetFromAxisProperties( m_plotWidget, RiuPlotAxis::defaultLeft(), m_yAxisProperties(), title, {} );
RimPlotAxisTools::updatePlotWidgetFromAxisProperties( m_plotWidget, RiuPlotAxis::defaultBottom(), m_xAxisProperties(), m_xAxisTitle, {} );
RimPlotAxisTools::updatePlotWidgetFromAxisProperties( m_plotWidget, RiuPlotAxis::defaultLeft(), m_yAxisProperties(), m_yAxisTitle, {} );
m_plotWidget->scheduleReplot();
}
@ -267,7 +291,47 @@ void RimCustomVfpPlot::updateLegend()
//--------------------------------------------------------------------------------------------------
QString RimCustomVfpPlot::asciiDataForPlotExport() const
{
return {};
QString asciiData;
size_t plotCurveIdx = 0;
for ( const auto& curveData : m_plotData )
{
for ( size_t curveIdx = 0; curveIdx < curveData.size(); curveIdx++ )
{
asciiData += curveData.curveTitle( curveIdx );
if ( !m_additionalDataSources.empty() && plotCurveIdx < m_plotCurveMetaData.size() )
{
auto plotCurveData = m_plotCurveMetaData[plotCurveIdx];
asciiData += QString( " (Table: %1)" ).arg( plotCurveData.tableNumber );
}
asciiData += "\n";
QTextStream stream( &asciiData );
RifCsvDataTableFormatter formatter( stream, RiaPreferences::current()->csvTextExportFieldSeparator );
std::vector<RifTextDataTableColumn> header;
const int precision = 2;
header.emplace_back( curveData.xAxisTitle(), RifTextDataTableDoubleFormatting( RIF_FLOAT, precision ) );
header.emplace_back( curveData.yAxisTitle(), RifTextDataTableDoubleFormatting( RIF_FLOAT, precision ) );
formatter.header( header );
for ( size_t i = 0; i < curveData.xData( curveIdx ).size(); i++ )
{
formatter.add( curveData.xData( curveIdx )[i] );
formatter.add( curveData.yData( curveIdx )[i] );
formatter.rowCompleted();
}
formatter.tableCompleted();
plotCurveIdx++;
}
asciiData += "\n";
}
return asciiData;
}
//--------------------------------------------------------------------------------------------------
@ -275,7 +339,7 @@ QString RimCustomVfpPlot::asciiDataForPlotExport() const
//--------------------------------------------------------------------------------------------------
void RimCustomVfpPlot::reattachAllCurves()
{
for ( auto curve : m_plotCurves() )
for ( const auto& curve : m_plotCurves() )
{
if ( curve->isChecked() )
{
@ -289,7 +353,7 @@ void RimCustomVfpPlot::reattachAllCurves()
//--------------------------------------------------------------------------------------------------
void RimCustomVfpPlot::detachAllCurves()
{
for ( auto curve : m_plotCurves() )
for ( const auto& curve : m_plotCurves() )
{
curve->detach();
}
@ -308,35 +372,43 @@ QString RimCustomVfpPlot::description() const
//--------------------------------------------------------------------------------------------------
QString RimCustomVfpPlot::infoForCurve( RimPlotCurve* plotCurve ) const
{
std::vector<RimVfpTable*> tables = m_additionalDataSources.ptrReferencedObjectsByType();
tables.push_back( m_mainDataSource );
auto plotCurveIdx = m_plotCurves.indexOf( plotCurve );
auto index = m_plotCurves.indexOf( plotCurve );
size_t curveCount = 0;
for ( size_t i = 0; i < m_plotData.size(); i++ )
if ( plotCurveIdx < m_plotCurveMetaData.size() )
{
curveCount += m_plotData[i].size();
if ( index < curveCount )
{
auto tableIndex = i;
auto values = m_plotCurveMetaData[plotCurveIdx];
QString info = QString( "Table: %1\n" ).arg( values.tableNumber );
info += values.curveName;
auto table = tables[tableIndex];
QString info = QString( "Table: %1" ).arg( table->tableNumber() );
if ( m_familyVariable() != RimVfpDefines::ProductionVariableType::WATER_CUT && m_waterCut().size() > 1 )
info += QString( "\nWC: %1 %2" )
.arg( convertToDisplayUnit( values.waterCutValue, RimVfpDefines::ProductionVariableType::WATER_CUT ) )
.arg( getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType::WATER_CUT ) );
auto curveIndex = index - ( curveCount - m_plotData[i].size() );
auto selection = tableSelection( table );
if ( curveIndex < selection.familyValues.size() )
{
auto displayValue = convertToDisplayUnit( selection.familyValues[curveIndex], m_familyVariable() );
auto unitText = getDisplayUnit( m_familyVariable() );
auto variableName = m_familyVariable().uiText();
if ( m_familyVariable() != RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO && m_gasLiquidRatio().size() > 1 )
info += QString( "\nGLR: %1 %2" )
.arg( convertToDisplayUnit( values.gasLiquidRatioValue, RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO ) )
.arg( getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO ) );
info += QString( " - %1 %2 %3 " ).arg( variableName ).arg( displayValue ).arg( unitText );
}
if ( m_familyVariable() != RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY && m_artificialLiftQuantity().size() > 1 )
info += QString( "\nLift: %1 %2" )
.arg( convertToDisplayUnit( values.artificialLiftQuantityValue,
RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY ) )
.arg( getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY ) );
return info;
}
if ( m_familyVariable() != RimVfpDefines::ProductionVariableType::THP && m_thp().size() > 1 )
info += QString( "\nTPH: %1 %2" )
.arg( convertToDisplayUnit( values.thpValue, RimVfpDefines::ProductionVariableType::THP ) )
.arg( getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType::THP ) );
if ( m_familyVariable() != RimVfpDefines::ProductionVariableType::FLOW_RATE && m_flowRate().size() > 1 )
info += QString( "\nRate: %1 %2" )
.arg( convertToDisplayUnit( values.flowRateValue, RimVfpDefines::ProductionVariableType::FLOW_RATE ) )
.arg( getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType::FLOW_RATE ) );
info += "\n";
return info;
}
return {};
@ -470,6 +542,27 @@ void RimCustomVfpPlot::deleteViewWidget()
}
}
//--------------------------------------------------------------------------------------------------
/// Create all possible combinations of the vectors passed in.
//--------------------------------------------------------------------------------------------------
void generateCombinations( const std::vector<std::vector<double>>& vectors,
std::vector<double>& currentCombination,
std::vector<std::vector<double>>& allCombinations,
size_t depth )
{
if ( depth == vectors.size() )
{
allCombinations.push_back( currentCombination );
return;
}
for ( const auto& value : vectors[depth] )
{
currentCombination[depth] = value;
generateCombinations( vectors, currentCombination, allCombinations, depth + 1 );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -500,26 +593,86 @@ void RimCustomVfpPlot::onLoadDataAndUpdate()
tables.push_back( m_mainDataSource );
m_plotData.clear();
m_plotCurveMetaData.clear();
for ( const auto& table : tables )
{
if ( !table ) continue;
int tableIndex = table->tableNumber();
auto vfpTables = table->dataSource()->vfpTables();
int tableNumber = table->tableNumber();
auto vfpTables = table->dataSource()->vfpTables();
auto vfpPlotData = vfpTables->populatePlotData( tableIndex,
m_primaryVariable(),
m_familyVariable(),
m_interpolatedVariable(),
m_flowingPhase(),
tableSelection( table ) );
if ( table->tableType() == RimVfpDefines::TableType::INJECTION )
{
auto vfpPlotData = vfpTables->populatePlotData( tableNumber,
m_primaryVariable(),
m_familyVariable(),
m_interpolatedVariable(),
m_flowingPhase(),
VfpTableSelection() );
m_plotData.push_back( vfpPlotData );
m_plotData.push_back( vfpPlotData );
QColor curveColor = RiaColorTables::summaryCurveDefaultPaletteColors().cycledQColor( colorIndex++ );
QColor curveColor = curveColors().cycledQColor( colorIndex );
populatePlotWidgetWithPlotData( m_plotWidget, vfpPlotData, curveColor );
auto symbols = curveSymbols();
auto symbol = symbols[colorIndex % symbols.size()];
bool multipleCurveSets = tables.size() > 1;
CurveNameContent curveNameContent;
curveNameContent.defaultName = true;
populatePlotWidgetWithPlotData( m_plotWidget,
vfpPlotData,
VfpValueSelection(),
tableNumber,
curveColor,
symbol,
multipleCurveSets,
curveNameContent );
colorIndex++;
}
else
{
auto valueSelections = computeValueSelectionCombinations();
for ( auto& valueSelection : valueSelections )
{
valueSelection.familyValues = familyValuesForTable( table );
auto vfpPlotData = vfpTables->populatePlotData( tableNumber,
m_primaryVariable(),
m_familyVariable(),
m_interpolatedVariable(),
m_flowingPhase(),
valueSelection );
m_plotData.push_back( vfpPlotData );
QColor curveColor = curveColors().cycledQColor( colorIndex );
auto symbols = curveSymbols();
auto symbol = symbols[colorIndex % symbols.size()];
bool multipleCurveSets = ( tables.size() > 1 || ( valueSelections.size() > 1 ) );
CurveNameContent curveNameContent;
if ( tables.size() > 1 ) curveNameContent.tableNumber = true;
if ( m_flowRate().size() > 1 ) curveNameContent.flowRate = true;
if ( m_thp().size() > 1 ) curveNameContent.thp = true;
if ( m_artificialLiftQuantity().size() > 1 ) curveNameContent.artificialLiftQuantity = true;
if ( m_waterCut().size() > 1 ) curveNameContent.waterCut = true;
if ( m_gasLiquidRatio().size() > 1 ) curveNameContent.gasLiquidRatio = true;
populatePlotWidgetWithPlotData( m_plotWidget,
vfpPlotData,
valueSelection,
tableNumber,
curveColor,
symbol,
multipleCurveSets,
curveNameContent );
colorIndex++;
}
}
}
updatePlotTitle(
@ -538,36 +691,108 @@ void RimCustomVfpPlot::onLoadDataAndUpdate()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimCustomVfpPlot::populatePlotWidgetWithPlotData( RiuPlotWidget* plotWidget, const VfpPlotData& plotData, const QColor& color )
void RimCustomVfpPlot::populatePlotWidgetWithPlotData( RiuPlotWidget* plotWidget,
const VfpPlotData& plotData,
const VfpValueSelection& valueSelection,
int tableNumber,
const QColor& color,
RiuPlotCurveSymbol::PointSymbolEnum curveSymbol,
bool multipleCurveSets,
const CurveNameContent& curveNameContent )
{
if ( !plotWidget ) return;
plotWidget->setAxisScale( RiuPlotAxis::defaultBottom(), 0, 1 );
plotWidget->setAxisScale( RiuPlotAxis::defaultLeft(), 0, 1 );
plotWidget->setAxisAutoScale( RiuPlotAxis::defaultBottom(), true );
plotWidget->setAxisAutoScale( RiuPlotAxis::defaultLeft(), true );
plotWidget->setAxisTitleText( RiuPlotAxis::defaultBottom(), plotData.xAxisTitle() );
plotWidget->setAxisTitleText( RiuPlotAxis::defaultLeft(), plotData.yAxisTitle() );
for ( auto idx = 0u; idx < plotData.size(); idx++ )
m_xAxisTitle = plotData.xAxisTitle();
m_yAxisTitle = plotData.yAxisTitle();
auto formatCurveNamePart =
[&]( RimVfpDefines::ProductionVariableType variableType, double familyValue, double selectionValue, const QString& namePart ) -> QString
{
double value = ( variableType == m_familyVariable() ) ? familyValue : selectionValue;
double displayValue = convertToDisplayUnit( value, variableType );
return QString( " %1:%2" ).arg( namePart ).arg( displayValue );
};
for ( auto curveIndex = 0u; curveIndex < plotData.size(); curveIndex++ )
{
auto curve = new RimPlotCurve();
curve->setLineStyle( RiuQwtPlotCurveDefines::LineStyleEnum::STYLE_SOLID );
curve->setLineThickness( 2 );
curve->setColor( RiaColorTools::fromQColorTo3f( color ) );
curve->setSymbol( RiuPlotCurveSymbol::SYMBOL_ELLIPSE );
curve->setSymbolSize( 6 );
curve->setLineThickness( m_curveThickness() );
curve->setCustomName( plotData.curveTitle( idx ) );
if ( multipleCurveSets )
{
// Use the incoming color for all curves, and cycle the symbols
curve->setColor( RiaColorTools::fromQColorTo3f( color ) );
auto symbols = curveSymbols();
auto customSymbol = symbols[curveIndex % symbols.size()];
curve->setSymbol( customSymbol );
}
else
{
// Use the incoming symbol for all curves, and cycle the colors
auto customColor = curveColors().cycledQColor( curveIndex );
curve->setColor( RiaColorTools::fromQColorTo3f( customColor ) );
curve->setSymbol( curveSymbol );
}
curve->setSymbolSize( m_curveSymbolSize() );
QString curveName;
if ( curveNameContent.defaultName ) curveName = plotData.curveTitle( curveIndex );
if ( curveNameContent.tableNumber ) curveName += QString( " Table:%1" ).arg( tableNumber );
auto familyValue = ( curveIndex < valueSelection.familyValues.size() ) ? valueSelection.familyValues[curveIndex] : 0.0;
using pvt = RimVfpDefines::ProductionVariableType;
if ( curveNameContent.thp || m_familyVariable() == pvt::THP )
{
curveName += formatCurveNamePart( pvt::THP, familyValue, valueSelection.thpValue, "THP" );
}
if ( curveNameContent.gasLiquidRatio || m_familyVariable() == pvt::GAS_LIQUID_RATIO )
{
curveName += formatCurveNamePart( pvt::GAS_LIQUID_RATIO, familyValue, valueSelection.gasLiquidRatioValue, "GLR" );
}
if ( curveNameContent.waterCut || m_familyVariable() == pvt::WATER_CUT )
{
curveName += formatCurveNamePart( pvt::WATER_CUT, familyValue, valueSelection.waterCutValue, "WC" );
}
if ( curveNameContent.artificialLiftQuantity || m_familyVariable() == pvt::ARTIFICIAL_LIFT_QUANTITY )
{
curveName += formatCurveNamePart( pvt::ARTIFICIAL_LIFT_QUANTITY, familyValue, valueSelection.artificialLiftQuantityValue, "Lift" );
}
if ( curveNameContent.flowRate || m_familyVariable() == pvt::FLOW_RATE )
{
curveName += formatCurveNamePart( pvt::FLOW_RATE, familyValue, valueSelection.flowRateValue, "Rate" );
}
curve->setCustomName( curveName.trimmed() );
curve->setParentPlotNoReplot( plotWidget );
if ( curve->plotCurve() )
{
bool useLogarithmicScale = false;
curve->plotCurve()->setSamplesFromXValuesAndYValues( plotData.xData( idx ), plotData.yData( idx ), useLogarithmicScale );
curve->plotCurve()->setSamplesFromXValuesAndYValues( plotData.xData( curveIndex ), plotData.yData( curveIndex ), useLogarithmicScale );
}
curve->updateCurveAppearance();
curve->appearanceChanged.connect( this, &RimCustomVfpPlot::curveAppearanceChanged );
m_plotCurves.push_back( curve );
PlotCurveData plotCurveData;
plotCurveData.curveName = plotData.curveTitle( curveIndex );
plotCurveData.tableNumber = tableNumber;
plotCurveData.flowRateValue = valueSelection.flowRateValue;
plotCurveData.thpValue = valueSelection.thpValue;
plotCurveData.artificialLiftQuantityValue = valueSelection.artificialLiftQuantityValue;
plotCurveData.waterCutValue = valueSelection.waterCutValue;
plotCurveData.gasLiquidRatioValue = valueSelection.gasLiquidRatioValue;
m_plotCurveMetaData.emplace_back( plotCurveData );
}
updateConnectedEditors();
@ -674,7 +899,7 @@ std::vector<double> RimCustomVfpPlot::availableValues( RimVfpDefines::Production
auto values = m_mainDataSource->dataSource()->vfpTables()->getProductionTableData( m_tableNumber(), variableType );
if ( m_curveOptionFiltering() == RimVfpDefines::CurveOptionValuesType::UNION_OF_SELECTED_TABLES )
if ( m_curveValueOptions() == RimVfpDefines::CurveOptionValuesType::UNION_OF_SELECTED_TABLES )
{
std::vector<RimVfpTable*> tables = m_additionalDataSources.ptrReferencedObjectsByType();
for ( const auto& table : tables )
@ -701,6 +926,107 @@ RiuPlotCurveInfoTextProvider* RimCustomVfpPlot::curveTextProvider()
return &textProvider;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimVfpDefines::ProductionVariableType> RimCustomVfpPlot::nonFamilyProductionVariables() const
{
std::vector<RimVfpDefines::ProductionVariableType> variables;
auto allVariables = { RimVfpDefines::ProductionVariableType::FLOW_RATE,
RimVfpDefines::ProductionVariableType::THP,
RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY,
RimVfpDefines::ProductionVariableType::WATER_CUT,
RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO };
for ( const auto& variable : allVariables )
{
if ( variable != m_familyVariable() )
{
variables.push_back( variable );
}
}
return variables;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<VfpValueSelection> RimCustomVfpPlot::computeValueSelectionCombinations() const
{
auto populateValueSelection = []( VfpValueSelection& selection, RimVfpDefines::ProductionVariableType variableType, double value )
{
switch ( variableType )
{
case RimVfpDefines::ProductionVariableType::FLOW_RATE:
selection.flowRateValue = value;
break;
case RimVfpDefines::ProductionVariableType::THP:
selection.thpValue = value;
break;
case RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY:
selection.artificialLiftQuantityValue = value;
break;
case RimVfpDefines::ProductionVariableType::WATER_CUT:
selection.waterCutValue = value;
break;
case RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO:
selection.gasLiquidRatioValue = value;
break;
}
};
auto availableVariables = nonFamilyProductionVariables();
std::vector<std::vector<double>> variableVectors;
for ( auto variableType : availableVariables )
{
variableVectors.push_back( valuesForProductionType( variableType ) );
}
std::vector<std::vector<double>> allCombinations;
std::vector<double> currentCombination( variableVectors.size() );
generateCombinations( variableVectors, currentCombination, allCombinations, 0 );
std::vector<VfpValueSelection> valueSelections;
for ( const auto& combination : allCombinations )
{
VfpValueSelection selection;
for ( size_t i = 0; i < availableVariables.size(); ++i )
{
populateValueSelection( selection, availableVariables[i], combination[i] );
}
valueSelections.push_back( selection );
}
return valueSelections;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RiuPlotCurveSymbol::PointSymbolEnum> RimCustomVfpPlot::curveSymbols()
{
return {
RiuPlotCurveSymbol::SYMBOL_ELLIPSE,
RiuPlotCurveSymbol::SYMBOL_CROSS,
RiuPlotCurveSymbol::SYMBOL_DIAMOND,
RiuPlotCurveSymbol::SYMBOL_XCROSS,
RiuPlotCurveSymbol::SYMBOL_LEFT_TRIANGLE,
RiuPlotCurveSymbol::SYMBOL_STAR1,
RiuPlotCurveSymbol::SYMBOL_RIGHT_TRIANGLE,
};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const caf::ColorTable RimCustomVfpPlot::curveColors()
{
return RiaColorTables::summaryCurveDefaultPaletteColors().inverted();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -772,54 +1098,59 @@ QString RimCustomVfpPlot::getDisplayUnit( RimVfpDefines::ProductionVariableType
void RimCustomVfpPlot::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
uiOrdering.add( &m_mainDataSource );
uiOrdering.add( &m_additionalDataSources );
uiOrdering.add( &m_curveMatchingType );
uiOrdering.add( &m_curveOptionFiltering );
{
auto group = uiOrdering.addNewGroup( "Configuration" );
group->add( &m_curveMatchingType );
group->add( &m_curveValueOptions );
group->add( &m_interpolatedVariable );
if ( m_tableType == RimVfpDefines::TableType::PRODUCTION )
{
group->add( &m_primaryVariable );
group->add( &m_familyVariable );
}
}
uiOrdering.add( &m_tableType );
uiOrdering.add( &m_tableNumber );
uiOrdering.add( &m_referenceDepth );
uiOrdering.add( &m_interpolatedVariable );
uiOrdering.add( &m_flowingPhase );
{
auto group = uiOrdering.addNewGroup( "Table Details" );
group->add( &m_tableType );
group->add( &m_tableNumber );
group->add( &m_referenceDepth );
group->add( &m_flowingPhase );
if ( m_tableType == RimVfpDefines::TableType::PRODUCTION )
{
group->add( &m_flowingWaterFraction );
group->add( &m_flowingGasFraction );
}
}
{
auto group = uiOrdering.addNewGroup( "Additional Tables" );
group->setCollapsedByDefault();
group->add( &m_additionalDataSources );
}
if ( m_tableType == RimVfpDefines::TableType::PRODUCTION )
{
uiOrdering.add( &m_flowingWaterFraction );
uiOrdering.add( &m_flowingGasFraction );
auto selectionDetailsGroup = uiOrdering.addNewGroup( "Selection Details" );
selectionDetailsGroup->setCollapsedByDefault();
selectionDetailsGroup->add( &m_flowRate );
selectionDetailsGroup->add( &m_thp );
selectionDetailsGroup->add( &m_artificialLiftQuantity );
selectionDetailsGroup->add( &m_waterCut );
selectionDetailsGroup->add( &m_gasLiquidRatio );
}
uiOrdering.add( &m_primaryVariable );
uiOrdering.add( &m_familyVariable );
caf::PdmUiOrdering* fixedVariablesGroup = uiOrdering.addNewGroup( "Fixed Variables" );
fixedVariablesGroup->add( &m_flowRateIdx );
fixedVariablesGroup->add( &m_thpIdx );
fixedVariablesGroup->add( &m_articifialLiftQuantityIdx );
fixedVariablesGroup->add( &m_waterCutIdx );
fixedVariablesGroup->add( &m_gasLiquidRatioIdx );
fixedVariablesGroup->add( &m_familyValues );
// Disable the choices for variables as primary or family
setFixedVariableUiEditability( m_flowRateIdx, RimVfpDefines::ProductionVariableType::FLOW_RATE );
setFixedVariableUiEditability( m_thpIdx, RimVfpDefines::ProductionVariableType::THP );
setFixedVariableUiEditability( m_articifialLiftQuantityIdx, RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY );
setFixedVariableUiEditability( m_waterCutIdx, RimVfpDefines::ProductionVariableType::WATER_CUT );
setFixedVariableUiEditability( m_gasLiquidRatioIdx, RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO );
{
auto group = uiOrdering.addNewGroup( "Appearance" );
group->add( &m_curveThickness );
group->add( &m_curveSymbolSize );
}
uiOrdering.skipRemainingFields( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimCustomVfpPlot::setFixedVariableUiEditability( caf::PdmFieldHandle& field, RimVfpDefines::ProductionVariableType variableType )
{
field.uiCapability()->setUiReadOnly( variableType == m_primaryVariable.v() );
field.uiCapability()->setUiHidden( variableType == m_familyVariable.v() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -827,36 +1158,31 @@ QList<caf::PdmOptionItemInfo> RimCustomVfpPlot::calculateValueOptions( const caf
{
QList<caf::PdmOptionItemInfo> options = RimPlot::calculateValueOptions( fieldNeedingOptions );
if ( fieldNeedingOptions == &m_flowRateIdx )
if ( fieldNeedingOptions == &m_flowRate )
{
calculateTableValueOptions( RimVfpDefines::ProductionVariableType::FLOW_RATE, options );
}
else if ( fieldNeedingOptions == &m_thpIdx )
else if ( fieldNeedingOptions == &m_thp )
{
calculateTableValueOptions( RimVfpDefines::ProductionVariableType::THP, options );
}
else if ( fieldNeedingOptions == &m_articifialLiftQuantityIdx )
else if ( fieldNeedingOptions == &m_artificialLiftQuantity )
{
calculateTableValueOptions( RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY, options );
}
else if ( fieldNeedingOptions == &m_waterCutIdx )
else if ( fieldNeedingOptions == &m_waterCut )
{
calculateTableValueOptions( RimVfpDefines::ProductionVariableType::WATER_CUT, options );
}
else if ( fieldNeedingOptions == &m_gasLiquidRatioIdx )
else if ( fieldNeedingOptions == &m_gasLiquidRatio )
{
calculateTableValueOptions( RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO, options );
}
else if ( fieldNeedingOptions == &m_familyValues )
{
calculateTableValueOptions( m_familyVariable(), options );
}
else if ( fieldNeedingOptions == &m_additionalDataSources )
{
RimVfpDataCollection* vfpDataCollection = RimVfpDataCollection::instance();
@ -878,9 +1204,60 @@ QList<caf::PdmOptionItemInfo> RimCustomVfpPlot::calculateValueOptions( const caf
}
}
else if ( fieldNeedingOptions == &m_curveThickness )
{
for ( size_t i = 0; i < 10; i++ )
{
options.push_back( caf::PdmOptionItemInfo( QString::number( i + 1 ), QVariant::fromValue( i + 1 ) ) );
}
}
return options;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimCustomVfpPlot::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute )
{
if ( auto attrib = dynamic_cast<caf::PdmUiTreeSelectionEditorAttribute*>( attribute ) )
{
attrib->showTextFilter = false;
}
if ( field == &m_mainDataSource )
{
if ( auto* myAttr = dynamic_cast<caf::PdmUiComboBoxEditorAttribute*>( attribute ) )
{
myAttr->showPreviousAndNextButtons = true;
myAttr->nextIcon = QIcon( ":/ComboBoxDown.svg" );
myAttr->previousIcon = QIcon( ":/ComboBoxUp.svg" );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RimCustomVfpPlot::valuesForProductionType( RimVfpDefines::ProductionVariableType variableType ) const
{
switch ( variableType )
{
case RimVfpDefines::ProductionVariableType::FLOW_RATE:
return m_flowRate();
case RimVfpDefines::ProductionVariableType::THP:
return m_thp();
case RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY:
return m_artificialLiftQuantity();
case RimVfpDefines::ProductionVariableType::WATER_CUT:
return m_waterCut();
case RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO:
return m_gasLiquidRatio();
}
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -888,11 +1265,11 @@ void RimCustomVfpPlot::calculateTableValueOptions( RimVfpDefines::ProductionVari
{
auto values = availableValues( variableType );
for ( size_t i = 0; i < values.size(); i++ )
for ( double value : values )
{
options.push_back(
caf::PdmOptionItemInfo( QString( "%1 %2" ).arg( convertToDisplayUnit( values[i], variableType ) ).arg( getDisplayUnit( variableType ) ),
values[i] ) );
caf::PdmOptionItemInfo( QString( "%1 %2" ).arg( convertToDisplayUnit( value, variableType ) ).arg( getDisplayUnit( variableType ) ),
value ) );
}
}
@ -906,11 +1283,14 @@ void RimCustomVfpPlot::fieldChangedByUi( const caf::PdmFieldHandle* changedField
if ( changedField == &m_mainDataSource )
{
initializeObject();
initializeSelection();
zoomAll();
}
if ( changedField == &m_familyVariable || changedField == &m_curveOptionFiltering )
if ( changedField == &m_additionalDataSources || changedField == &m_curveMatchingType || changedField == &m_curveValueOptions ||
changedField == &m_primaryVariable || changedField == &m_familyVariable )
{
m_familyValues.v() = availableValues( m_familyVariable() );
initializeSelection();
}
loadDataAndUpdate();
@ -918,13 +1298,6 @@ void RimCustomVfpPlot::fieldChangedByUi( const caf::PdmFieldHandle* changedField
updateConnectedEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimCustomVfpPlot::initAfterRead()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -981,33 +1354,30 @@ void RimCustomVfpPlot::scheduleReplot()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
VfpValueSelection RimCustomVfpPlot::tableSelection( RimVfpTable* table ) const
std::vector<double> RimCustomVfpPlot::familyValuesForTable( RimVfpTable* table ) const
{
VfpValueSelection selection;
if ( !table || !m_mainDataSource || !m_mainDataSource->dataSource() || !m_mainDataSource->dataSource()->vfpTables() ) return {};
selection.articifialLiftQuantityValue = m_articifialLiftQuantityIdx();
selection.flowRateValue = m_flowRateIdx();
selection.gasLiquidRatioValue = m_gasLiquidRatioIdx();
selection.thpValue = m_thpIdx();
selection.waterCutValue = m_waterCutIdx();
std::vector<double> mainTableFamilyValues = valuesForProductionType( m_familyVariable() );
if ( m_curveMatchingType() == RimVfpDefines::CurveMatchingType::EXACT )
{
selection.familyValues = m_familyValues();
}
else if ( m_curveMatchingType() == RimVfpDefines::CurveMatchingType::CLOSEST_MATCH_FAMILY )
{
auto familyValues = m_familyValues();
if ( table && table->dataSource() && table->dataSource()->vfpTables() )
{
auto valuesToMatch = table->dataSource()->vfpTables()->getProductionTableData( table->tableNumber(), m_familyVariable() );
auto indices = RigVfpTables::uniqueClosestIndices( familyValues, valuesToMatch );
for ( const auto& i : indices )
{
selection.familyValues.push_back( valuesToMatch[i] );
}
}
return mainTableFamilyValues;
}
return selection;
if ( m_curveMatchingType() == RimVfpDefines::CurveMatchingType::CLOSEST_MATCH_FAMILY )
{
auto valuesToMatch = table->dataSource()->vfpTables()->getProductionTableData( table->tableNumber(), m_familyVariable() );
auto indices = RigVfpTables::uniqueClosestIndices( mainTableFamilyValues, valuesToMatch );
std::vector<double> values;
for ( const auto& i : indices )
{
values.push_back( valuesToMatch[i] );
}
return values;
}
return {};
}

View File

@ -21,6 +21,8 @@
#include "RimPlot.h"
#include "RimVfpDefines.h"
#include "RiuPlotCurveSymbol.h"
#include "cafPdmPtrArrayField.h"
#include "cafPdmPtrField.h"
@ -43,6 +45,11 @@ class VFPInjTable;
class VFPProdTable;
} // namespace Opm
namespace caf
{
class ColorTable;
}
//--------------------------------------------------------------------------------------------------
/// Vertical Flow Performance Plot
//--------------------------------------------------------------------------------------------------
@ -57,6 +64,7 @@ public:
void selectDataSource( RimVfpTable* mainDataSource, const std::vector<RimVfpTable*>& vfpTableData );
void setTableNumber( int tableNumber );
void initializeObject();
void initializeSelection();
// RimPlot implementations
RiuPlotWidget* plotWidget() override;
@ -88,21 +96,19 @@ private:
void scheduleReplot();
private:
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
void initAfterRead() override;
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
VfpValueSelection tableSelection( RimVfpTable* table ) const;
void initializeFromInitData( const VfpTableInitialData& table );
std::vector<double> valuesForProductionType( RimVfpDefines::ProductionVariableType variableType ) const;
std::vector<double> familyValuesForTable( RimVfpTable* table ) const;
void initializeFromInitData( const VfpTableInitialData& table );
RiuPlotWidget* doCreatePlotViewWidget( QWidget* mainWindowParent ) override;
void calculateTableValueOptions( RimVfpDefines::ProductionVariableType variableType, QList<caf::PdmOptionItemInfo>& options );
void setFixedVariableUiEditability( caf::PdmFieldHandle& field, RimVfpDefines::ProductionVariableType variableType );
void updatePlotTitle( const QString& plotTitle );
static QString generatePlotTitle( const QString& wellName,
int tableNumber,
@ -116,7 +122,25 @@ private:
static QString getDisplayUnit( RimVfpDefines::ProductionVariableType variableType );
static QString getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType variableType );
void populatePlotWidgetWithPlotData( RiuPlotWidget* plotWidget, const VfpPlotData& plotData, const QColor& color );
struct CurveNameContent
{
bool defaultName = false;
bool tableNumber = false;
bool flowRate = false;
bool thp = false;
bool artificialLiftQuantity = false;
bool waterCut = false;
bool gasLiquidRatio = false;
};
void populatePlotWidgetWithPlotData( RiuPlotWidget* plotWidget,
const VfpPlotData& plotData,
const VfpValueSelection& valueSelection,
int tableNumber,
const QColor& color,
RiuPlotCurveSymbol::PointSymbolEnum curveSymbol,
bool multipleCurveSets,
const CurveNameContent& curveNameContent );
static QString axisTitle( RimVfpDefines::ProductionVariableType variableType, RimVfpDefines::FlowingPhaseType flowingPhase );
@ -133,6 +157,24 @@ private:
static RiuPlotCurveInfoTextProvider* curveTextProvider();
std::vector<RimVfpDefines::ProductionVariableType> nonFamilyProductionVariables() const;
std::vector<VfpValueSelection> computeValueSelectionCombinations() const;
struct PlotCurveData
{
QString curveName;
int tableNumber;
double flowRateValue;
double thpValue;
double artificialLiftQuantityValue;
double waterCutValue;
double gasLiquidRatioValue;
};
static std::vector<RiuPlotCurveSymbol::PointSymbolEnum> curveSymbols();
static const caf::ColorTable curveColors();
private:
caf::PdmField<QString> m_plotTitle;
@ -140,7 +182,7 @@ private:
caf::PdmPtrArrayField<RimVfpTable*> m_additionalDataSources;
caf::PdmField<caf::AppEnum<RimVfpDefines::CurveMatchingType>> m_curveMatchingType;
caf::PdmField<caf::AppEnum<RimVfpDefines::CurveOptionValuesType>> m_curveOptionFiltering;
caf::PdmField<caf::AppEnum<RimVfpDefines::CurveOptionValuesType>> m_curveValueOptions;
caf::PdmField<int> m_tableNumber;
caf::PdmField<double> m_referenceDepth;
@ -153,20 +195,25 @@ private:
caf::PdmField<caf::AppEnum<RimVfpDefines::ProductionVariableType>> m_primaryVariable;
caf::PdmField<caf::AppEnum<RimVfpDefines::ProductionVariableType>> m_familyVariable;
caf::PdmField<double> m_flowRateIdx;
caf::PdmField<double> m_thpIdx;
caf::PdmField<double> m_articifialLiftQuantityIdx;
caf::PdmField<double> m_waterCutIdx;
caf::PdmField<double> m_gasLiquidRatioIdx;
caf::PdmField<std::vector<double>> m_familyValues;
caf::PdmField<std::vector<double>> m_flowRate;
caf::PdmField<std::vector<double>> m_thp;
caf::PdmField<std::vector<double>> m_artificialLiftQuantity;
caf::PdmField<std::vector<double>> m_waterCut;
caf::PdmField<std::vector<double>> m_gasLiquidRatio;
caf::PdmChildField<RimPlotAxisProperties*> m_yAxisProperties;
caf::PdmChildField<RimPlotAxisProperties*> m_xAxisProperties;
caf::PdmChildArrayField<RimPlotCurve*> m_plotCurves;
std::vector<VfpPlotData> m_plotData;
caf::PdmField<int> m_curveSymbolSize;
caf::PdmField<int> m_curveThickness;
std::vector<VfpPlotData> m_plotData;
std::vector<PlotCurveData> m_plotCurveMetaData;
QString m_xAxisTitle;
QString m_yAxisTitle;
QPointer<RiuPlotWidget> m_plotWidget;
};

View File

@ -85,7 +85,7 @@ void caf::AppEnum<RimVfpDefines::CurveMatchingType>::setUp()
{
addItem( RimVfpDefines::CurveMatchingType::EXACT, "EXACT", "Exact" );
addItem( RimVfpDefines::CurveMatchingType::CLOSEST_MATCH_FAMILY, "CLOSEST_MATCH_FAMILY", "Family Closest Match" );
setDefault( RimVfpDefines::CurveMatchingType::EXACT );
setDefault( RimVfpDefines::CurveMatchingType::CLOSEST_MATCH_FAMILY );
}
template <>

View File

@ -67,6 +67,7 @@ RimCustomVfpPlot* RimVfpPlotCollection::createAndAppendPlots( RimVfpTable* mainD
auto vfpPlot = new RimCustomVfpPlot();
vfpPlot->selectDataSource( mainDataSource, tableData );
vfpPlot->initializeObject();
vfpPlot->initializeSelection();
m_customVfpPlots.push_back( vfpPlot );

View File

@ -659,7 +659,7 @@ size_t RigVfpTables::getVariableIndexForValue( const Opm::VFPProdTable&
}
case RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY:
{
return findClosestIndexForVariable( targetVariable, valueSelection.articifialLiftQuantityValue, table );
return findClosestIndexForVariable( targetVariable, valueSelection.artificialLiftQuantityValue, table );
}
case RimVfpDefines::ProductionVariableType::FLOW_RATE:
{
@ -834,7 +834,7 @@ VfpTableInitialData RigVfpTables::getTableInitialData( int tableIndex ) const
auto prodTable = productionTable( tableIndex );
if ( prodTable.has_value() )
{
VfpTableInitialData initialData;
VfpTableInitialData initialData{};
initialData.isProductionTable = true;
initialData.tableNumber = prodTable->getTableNum();
initialData.datumDepth = prodTable->getDatumDepth();
@ -848,7 +848,7 @@ VfpTableInitialData RigVfpTables::getTableInitialData( int tableIndex ) const
auto injTable = injectionTable( tableIndex );
if ( injTable.has_value() )
{
VfpTableInitialData initialData;
VfpTableInitialData initialData{};
initialData.isProductionTable = false;
initialData.tableNumber = injTable->getTableNum();
initialData.datumDepth = injTable->getDatumDepth();

View File

@ -77,7 +77,7 @@ struct VfpValueSelection
{
double flowRateValue;
double thpValue;
double articifialLiftQuantityValue;
double artificialLiftQuantityValue;
double waterCutValue;
double gasLiquidRatioValue;