Files
ResInsight/ApplicationLibCode/ReservoirDataModel/RigVfpTables.cpp
Magne Sjaastad 1d57b9032b Custom vfp plot (#11450)
* AppFwk: When clearing a tree selection, make sure all values are cleared
* Fix deprecated implicit lambda
* Add support for using the closest value in addition to exact match
* Add table data source object and add plot with multiple data sources
Delete the temporary RimVfpDeck class
Add RimVfpTable to represent a table in a data source
Add plot able to show data from multiple tables

* AppFwk: Make it possible to call resolveReferences multiple times
Use case: Vfp tables are stored in files. Multiple tables can be present in one file. Pdm table objects are created after resolve references is done as part of parsing file. When the Pdm object are created, resolveReferences can be called once more.

* Call resolveReferencesRecursively() after RimVfpTable objects are created
2024-05-29 12:55:45 +02:00

861 lines
38 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2024 Equinor 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 "RigVfpTables.h"
#include "RiaEclipseUnitTools.h"
#include "cafAppEnum.h"
#include "opm/input/eclipse/Schedule/VFPInjTable.hpp"
#include "opm/input/eclipse/Schedule/VFPProdTable.hpp"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
VfpPlotData RigVfpTables::populatePlotData( const Opm::VFPInjTable& table,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase )
{
VfpPlotData plotData;
QString xAxisTitle = axisTitle( RimVfpDefines::ProductionVariableType::FLOW_RATE, flowingPhase );
plotData.setXAxisTitle( xAxisTitle );
QString yAxisTitle = QString( "%1 %2" ).arg( caf::AppEnum<RimVfpDefines::InterpolatedVariableType>::uiText( interpolatedVariable ),
getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType::THP ) );
plotData.setYAxisTitle( yAxisTitle );
std::vector<double> thpValues = table.getTHPAxis();
for ( size_t thp = 0; thp < thpValues.size(); thp++ )
{
size_t numValues = table.getFloAxis().size();
std::vector<double> xVals = table.getFloAxis();
std::vector<double> yVals( numValues, 0.0 );
for ( size_t y = 0; y < numValues; y++ )
{
yVals[y] = table( thp, y );
if ( interpolatedVariable == RimVfpDefines::InterpolatedVariableType::BHP_THP_DIFF )
{
yVals[y] -= thpValues[thp];
}
}
double value = convertToDisplayUnit( thpValues[thp], RimVfpDefines::ProductionVariableType::THP );
QString unit = getDisplayUnit( RimVfpDefines::ProductionVariableType::THP );
QString title = QString( "%1 [%2]: %3" )
.arg( caf::AppEnum<RimVfpDefines::ProductionVariableType>::uiText( RimVfpDefines::ProductionVariableType::THP ) )
.arg( unit )
.arg( value );
convertToDisplayUnit( yVals, RimVfpDefines::ProductionVariableType::THP );
convertToDisplayUnit( xVals, RimVfpDefines::ProductionVariableType::FLOW_RATE );
plotData.appendCurve( title, xVals, yVals );
}
return plotData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
VfpPlotData RigVfpTables::populatePlotData( const Opm::VFPProdTable& table,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase,
const VfpTableSelection& tableSelection )
{
VfpPlotData plotData;
QString xAxisTitle = axisTitle( primaryVariable, flowingPhase );
plotData.setXAxisTitle( xAxisTitle );
QString yAxisTitle = QString( "%1 %2" ).arg( caf::AppEnum<RimVfpDefines::InterpolatedVariableType>::uiText( interpolatedVariable ),
getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType::THP ) );
plotData.setYAxisTitle( yAxisTitle );
size_t numFamilyValues = getProductionTableData( table, familyVariable ).size();
for ( size_t familyIdx = 0; familyIdx < numFamilyValues; familyIdx++ )
{
std::vector<double> primaryAxisValues = getProductionTableData( table, primaryVariable );
std::vector<double> familyVariableValues = getProductionTableData( table, familyVariable );
std::vector<double> thpValues = getProductionTableData( table, RimVfpDefines::ProductionVariableType::THP );
size_t numValues = primaryAxisValues.size();
std::vector<double> yVals( numValues, 0.0 );
for ( size_t y = 0; y < numValues; y++ )
{
size_t wfr_idx =
getVariableIndex( table, RimVfpDefines::ProductionVariableType::WATER_CUT, primaryVariable, y, familyVariable, familyIdx, tableSelection );
size_t gfr_idx = getVariableIndex( table,
RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO,
primaryVariable,
y,
familyVariable,
familyIdx,
tableSelection );
size_t alq_idx = getVariableIndex( table,
RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY,
primaryVariable,
y,
familyVariable,
familyIdx,
tableSelection );
size_t flo_idx =
getVariableIndex( table, RimVfpDefines::ProductionVariableType::FLOW_RATE, primaryVariable, y, familyVariable, familyIdx, tableSelection );
size_t thp_idx =
getVariableIndex( table, RimVfpDefines::ProductionVariableType::THP, primaryVariable, y, familyVariable, familyIdx, tableSelection );
yVals[y] = table( thp_idx, wfr_idx, gfr_idx, alq_idx, flo_idx );
if ( interpolatedVariable == RimVfpDefines::InterpolatedVariableType::BHP_THP_DIFF )
{
yVals[y] -= thpValues[thp_idx];
}
}
double familyValue = convertToDisplayUnit( familyVariableValues[familyIdx], familyVariable );
QString familyUnit = getDisplayUnit( familyVariable );
QString familyTitle = QString( "%1: %2 %3" )
.arg( caf::AppEnum<RimVfpDefines::ProductionVariableType>::uiText( familyVariable ) )
.arg( familyValue )
.arg( familyUnit );
convertToDisplayUnit( yVals, RimVfpDefines::ProductionVariableType::THP );
convertToDisplayUnit( primaryAxisValues, primaryVariable );
plotData.appendCurve( familyTitle, primaryAxisValues, yVals );
}
return plotData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
VfpPlotData RigVfpTables::populatePlotData( int tableIndex,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase,
const VfpTableSelection& tableSelection ) const
{
auto prodTable = productionTable( tableIndex );
if ( prodTable.has_value() )
{
return populatePlotData( *prodTable, primaryVariable, familyVariable, interpolatedVariable, flowingPhase, tableSelection );
};
auto injContainer = injectionTable( tableIndex );
if ( injContainer.has_value() )
{
return populatePlotData( *injContainer, interpolatedVariable, flowingPhase );
};
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
VfpPlotData RigVfpTables::populatePlotData( int tableIndex,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase,
const VfpValueSelection& valueSelection ) const
{
auto prodTable = productionTable( tableIndex );
if ( prodTable.has_value() )
{
return populatePlotData( *prodTable, primaryVariable, familyVariable, interpolatedVariable, flowingPhase, valueSelection );
}
auto injContainer = injectionTable( tableIndex );
if ( injContainer.has_value() )
{
return populatePlotData( *injContainer, interpolatedVariable, flowingPhase );
}
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
VfpPlotData RigVfpTables::populatePlotData( const Opm::VFPProdTable& table,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase,
const VfpValueSelection& valueSelection )
{
VfpPlotData plotData;
QString xAxisTitle = axisTitle( primaryVariable, flowingPhase );
plotData.setXAxisTitle( xAxisTitle );
QString yAxisTitle = QString( "%1 %2" ).arg( caf::AppEnum<RimVfpDefines::InterpolatedVariableType>::uiText( interpolatedVariable ),
getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType::THP ) );
plotData.setYAxisTitle( yAxisTitle );
std::vector<double> familyFilterValues = valueSelection.familyValues;
size_t numFamilyValues = getProductionTableData( table, familyVariable ).size();
for ( size_t familyIdx = 0; familyIdx < numFamilyValues; familyIdx++ )
{
std::vector<double> primaryAxisValues = getProductionTableData( table, primaryVariable );
std::vector<double> familyVariableValues = getProductionTableData( table, familyVariable );
std::vector<double> thpValues = getProductionTableData( table, RimVfpDefines::ProductionVariableType::THP );
// Skip if the family value is not in the filter
auto currentFamilyValue = familyVariableValues[familyIdx];
auto it = std::find( familyFilterValues.begin(), familyFilterValues.end(), currentFamilyValue );
if ( it == familyFilterValues.end() ) continue;
size_t numValues = primaryAxisValues.size();
std::vector<double> yVals( numValues, 0.0 );
for ( size_t y = 0; y < numValues; y++ )
{
auto currentPrimaryValue = primaryAxisValues[y];
size_t wfr_idx = getVariableIndexForValue( table,
RimVfpDefines::ProductionVariableType::WATER_CUT,
primaryVariable,
currentPrimaryValue,
familyVariable,
currentFamilyValue,
valueSelection );
size_t gfr_idx = getVariableIndexForValue( table,
RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO,
primaryVariable,
currentPrimaryValue,
familyVariable,
currentFamilyValue,
valueSelection );
size_t alq_idx = getVariableIndexForValue( table,
RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY,
primaryVariable,
currentPrimaryValue,
familyVariable,
currentFamilyValue,
valueSelection );
size_t flo_idx = getVariableIndexForValue( table,
RimVfpDefines::ProductionVariableType::FLOW_RATE,
primaryVariable,
currentPrimaryValue,
familyVariable,
currentFamilyValue,
valueSelection );
size_t thp_idx = getVariableIndexForValue( table,
RimVfpDefines::ProductionVariableType::THP,
primaryVariable,
currentPrimaryValue,
familyVariable,
currentFamilyValue,
valueSelection );
yVals[y] = table( thp_idx, wfr_idx, gfr_idx, alq_idx, flo_idx );
if ( interpolatedVariable == RimVfpDefines::InterpolatedVariableType::BHP_THP_DIFF )
{
yVals[y] -= thpValues[thp_idx];
}
}
double familyValue = convertToDisplayUnit( currentFamilyValue, familyVariable );
QString familyUnit = getDisplayUnit( familyVariable );
QString familyTitle = QString( "%1: %2 %3" )
.arg( caf::AppEnum<RimVfpDefines::ProductionVariableType>::uiText( familyVariable ) )
.arg( familyValue )
.arg( familyUnit );
convertToDisplayUnit( yVals, RimVfpDefines::ProductionVariableType::THP );
convertToDisplayUnit( primaryAxisValues, primaryVariable );
plotData.appendCurve( familyTitle, primaryAxisValues, yVals );
}
return plotData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RigVfpTables::asciiDataForTable( int tableNumber,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase,
const VfpTableSelection& tableSelection ) const
{
VfpPlotData plotData;
auto prodTable = productionTable( tableNumber );
if ( prodTable.has_value() )
{
plotData = populatePlotData( *prodTable, primaryVariable, familyVariable, interpolatedVariable, flowingPhase, tableSelection );
}
else
{
auto injTable = injectionTable( tableNumber );
if ( injTable.has_value() )
{
plotData = populatePlotData( *injTable, interpolatedVariable, flowingPhase );
}
}
return textForPlotData( plotData );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<int> RigVfpTables::findClosestIndices( const std::vector<double>& sourceValues, const std::vector<double>& valuesToMatch )
{
std::vector<int> result( sourceValues.size(), -1 );
// Returns the indices of the closest values in valuesToMatch for each value in sourceValues.
for ( size_t i = 0; i < sourceValues.size(); ++i )
{
double minDistance = std::numeric_limits<double>::max();
int closestIndex = -1;
for ( size_t j = 0; j < valuesToMatch.size(); ++j )
{
double distance = std::abs( sourceValues[i] - valuesToMatch[j] );
if ( distance < minDistance )
{
minDistance = distance;
closestIndex = static_cast<int>( j );
}
}
if ( closestIndex < static_cast<int>( valuesToMatch.size() ) )
{
result[i] = closestIndex;
}
}
return result;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<int> RigVfpTables::uniqueClosestIndices( const std::vector<double>& sourceValues, const std::vector<double>& valuesToMatch )
{
// Find the closest value in valuesForMatch for each value in sourceValues
std::vector<double> distances( sourceValues.size(), std::numeric_limits<double>::max() );
auto closestIndices = findClosestIndices( sourceValues, valuesToMatch );
for ( size_t i = 0; i < sourceValues.size(); i++ )
{
if ( closestIndices[i] >= 0 )
{
distances[i] = std::abs( sourceValues[i] - valuesToMatch[closestIndices[i]] );
}
}
while ( std::any_of( distances.begin(), distances.end(), []( double val ) { return val != std::numeric_limits<double>::max(); } ) )
{
// find the index of the smallest value in minDistance
auto minDistanceIt = std::min_element( distances.begin(), distances.end() );
if ( minDistanceIt == distances.end() )
{
break;
}
auto minDistanceIndex = std::distance( distances.begin(), minDistanceIt );
auto matchingIndex = closestIndices[minDistanceIndex];
if ( matchingIndex > -1 )
{
// Remove all references to the matching index
for ( size_t i = 0; i < sourceValues.size(); i++ )
{
if ( i == static_cast<size_t>( minDistanceIndex ) )
{
distances[i] = std::numeric_limits<double>::max();
}
else if ( closestIndices[i] == matchingIndex )
{
distances[i] = std::numeric_limits<double>::max();
closestIndices[i] = -1;
}
}
}
}
return closestIndices;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RigVfpTables::axisTitle( RimVfpDefines::ProductionVariableType variableType, RimVfpDefines::FlowingPhaseType flowingPhase )
{
QString title;
if ( flowingPhase == RimVfpDefines::FlowingPhaseType::GAS )
{
title = "Gas ";
}
else
{
title = "Liquid ";
}
title += QString( "%1 %2" ).arg( caf::AppEnum<RimVfpDefines::ProductionVariableType>::uiText( variableType ),
getDisplayUnitWithBracket( variableType ) );
return title;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RigVfpTables::getDisplayUnit( RimVfpDefines::ProductionVariableType variableType )
{
if ( variableType == RimVfpDefines::ProductionVariableType::THP ) return "Bar";
if ( variableType == RimVfpDefines::ProductionVariableType::FLOW_RATE ) return "Sm3/day";
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RigVfpTables::getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType variableType )
{
QString unit = getDisplayUnit( variableType );
if ( !unit.isEmpty() ) return QString( "[%1]" ).arg( unit );
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RigVfpTables::convertToDisplayUnit( double value, RimVfpDefines::ProductionVariableType variableType )
{
if ( variableType == RimVfpDefines::ProductionVariableType::THP )
{
return RiaEclipseUnitTools::pascalToBar( value );
}
if ( variableType == RimVfpDefines::ProductionVariableType::FLOW_RATE )
{
// Convert to m3/sec to m3/day
return value * static_cast<double>( 24 * 60 * 60 );
}
return value;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigVfpTables::convertToDisplayUnit( std::vector<double>& values, RimVfpDefines::ProductionVariableType variableType )
{
for ( double& value : values )
value = convertToDisplayUnit( value, variableType );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RigVfpTables::textForPlotData( const VfpPlotData& plotData )
{
QString dataText;
if ( plotData.size() > 0 )
{
// The curves should have same dimensions
const size_t curveSize = plotData.curveSize( 0 );
// Generate the headers for the columns
// First column is the primary variable
QString columnTitleLine( plotData.xAxisTitle() );
// Then one column per "family"
for ( size_t s = 0; s < plotData.size(); s++ )
{
columnTitleLine.append( QString( "\t%1" ).arg( plotData.curveTitle( s ) ) );
}
columnTitleLine.append( "\n" );
dataText.append( columnTitleLine );
// Add the rows: one row per primary variable value
for ( size_t idx = 0; idx < curveSize; idx++ )
{
QString line;
// First item on each line is the primary variable
line.append( QString( "%1" ).arg( plotData.xData( 0 )[idx] ) );
for ( size_t s = 0; s < plotData.size(); s++ )
{
line.append( QString( "\t%1" ).arg( plotData.yData( s )[idx] ) );
}
dataText.append( line );
dataText.append( "\n" );
}
}
return dataText;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RigVfpTables::getProductionTableData( const Opm::VFPProdTable& table, RimVfpDefines::ProductionVariableType variableType )
{
std::vector<double> xVals;
if ( variableType == RimVfpDefines::ProductionVariableType::WATER_CUT )
{
xVals = table.getWFRAxis();
}
else if ( variableType == RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO )
{
xVals = table.getGFRAxis();
}
else if ( variableType == RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY )
{
xVals = table.getALQAxis();
}
else if ( variableType == RimVfpDefines::ProductionVariableType::FLOW_RATE )
{
xVals = table.getFloAxis();
}
else if ( variableType == RimVfpDefines::ProductionVariableType::THP )
{
xVals = table.getTHPAxis();
}
return xVals;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RigVfpTables::getProductionTableData( int tableIndex, RimVfpDefines::ProductionVariableType variableType ) const
{
auto prodTable = productionTable( tableIndex );
if ( prodTable.has_value() )
{
return getProductionTableData( *prodTable, variableType );
}
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RigVfpTables::getVariableIndex( const Opm::VFPProdTable& table,
RimVfpDefines::ProductionVariableType targetVariable,
RimVfpDefines::ProductionVariableType primaryVariable,
size_t primaryValue,
RimVfpDefines::ProductionVariableType familyVariable,
size_t familyValue,
const VfpTableSelection& tableSelection )
{
if ( targetVariable == primaryVariable ) return primaryValue;
if ( targetVariable == familyVariable ) return familyValue;
if ( targetVariable == RimVfpDefines::ProductionVariableType::WATER_CUT ) return tableSelection.waterCutIdx;
if ( targetVariable == RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO ) return tableSelection.gasLiquidRatioIdx;
if ( targetVariable == RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY )
return tableSelection.articifialLiftQuantityIdx;
if ( targetVariable == RimVfpDefines::ProductionVariableType::FLOW_RATE ) return tableSelection.flowRateIdx;
if ( targetVariable == RimVfpDefines::ProductionVariableType::THP ) return tableSelection.thpIdx;
return getProductionTableData( table, targetVariable ).size() - 1;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RigVfpTables::getVariableIndexForValue( const Opm::VFPProdTable& table,
RimVfpDefines::ProductionVariableType targetVariable,
RimVfpDefines::ProductionVariableType primaryVariable,
double primaryValue,
RimVfpDefines::ProductionVariableType familyVariable,
double familyValue,
const VfpValueSelection& valueSelection )
{
auto findClosestIndex = []( const std::vector<double>& values, const double value )
{
auto it = std::lower_bound( values.begin(), values.end(), value );
if ( it == values.begin() )
{
return (size_t)0;
}
if ( it == values.end() )
{
return values.size() - 1;
}
if ( *it == value )
{
return (size_t)std::distance( values.begin(), it );
}
auto prev = it - 1;
if ( std::abs( *prev - value ) < std::abs( *it - value ) )
{
return (size_t)std::distance( values.begin(), prev );
}
return (size_t)std::distance( values.begin(), it );
};
if ( targetVariable == primaryVariable )
{
const auto values = getProductionTableData( table, targetVariable );
return findClosestIndex( values, primaryValue );
}
if ( targetVariable == familyVariable )
{
const auto values = getProductionTableData( table, targetVariable );
return findClosestIndex( values, familyValue );
}
auto findClosestIndexForVariable =
[&]( RimVfpDefines::ProductionVariableType targetVariable, const double selectedValue, const Opm::VFPProdTable& table )
{
const auto values = getProductionTableData( table, targetVariable );
return findClosestIndex( values, selectedValue );
};
switch ( targetVariable )
{
case RimVfpDefines::ProductionVariableType::WATER_CUT:
{
return findClosestIndexForVariable( targetVariable, valueSelection.waterCutValue, table );
}
case RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO:
{
return findClosestIndexForVariable( targetVariable, valueSelection.gasLiquidRatioValue, table );
}
case RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY:
{
return findClosestIndexForVariable( targetVariable, valueSelection.articifialLiftQuantityValue, table );
}
case RimVfpDefines::ProductionVariableType::FLOW_RATE:
{
return findClosestIndexForVariable( targetVariable, valueSelection.flowRateValue, table );
}
case RimVfpDefines::ProductionVariableType::THP:
{
return findClosestIndexForVariable( targetVariable, valueSelection.thpValue, table );
}
default:
break;
}
return 0;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::optional<Opm::VFPInjTable> RigVfpTables::injectionTable( int tableNumber ) const
{
for ( const auto& table : m_injectionTables )
{
if ( table.getTableNum() == tableNumber )
{
return table;
}
}
return std::nullopt;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::optional<Opm::VFPProdTable> RigVfpTables::productionTable( int tableNumber ) const
{
for ( const auto& table : m_productionTables )
{
if ( table.getTableNum() == tableNumber )
{
return table;
}
}
return std::nullopt;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpDefines::FlowingPhaseType RigVfpTables::getFlowingPhaseType( const Opm::VFPProdTable& table )
{
switch ( table.getFloType() )
{
case Opm::VFPProdTable::FLO_TYPE::FLO_OIL:
return RimVfpDefines::FlowingPhaseType::OIL;
case Opm::VFPProdTable::FLO_TYPE::FLO_GAS:
return RimVfpDefines::FlowingPhaseType::GAS;
case Opm::VFPProdTable::FLO_TYPE::FLO_LIQ:
return RimVfpDefines::FlowingPhaseType::LIQUID;
default:
return RimVfpDefines::FlowingPhaseType::INVALID;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpDefines::FlowingPhaseType RigVfpTables::getFlowingPhaseType( const Opm::VFPInjTable& table )
{
switch ( table.getFloType() )
{
case Opm::VFPInjTable::FLO_TYPE::FLO_OIL:
return RimVfpDefines::FlowingPhaseType::OIL;
case Opm::VFPInjTable::FLO_TYPE::FLO_GAS:
return RimVfpDefines::FlowingPhaseType::GAS;
case Opm::VFPInjTable::FLO_TYPE::FLO_WAT:
return RimVfpDefines::FlowingPhaseType::WATER;
default:
return RimVfpDefines::FlowingPhaseType::INVALID;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpDefines::FlowingWaterFractionType RigVfpTables::getFlowingWaterFractionType( const Opm::VFPProdTable& table )
{
switch ( table.getWFRType() )
{
case Opm::VFPProdTable::WFR_TYPE::WFR_WOR:
return RimVfpDefines::FlowingWaterFractionType::WOR;
case Opm::VFPProdTable::WFR_TYPE::WFR_WCT:
return RimVfpDefines::FlowingWaterFractionType::WCT;
case Opm::VFPProdTable::WFR_TYPE::WFR_WGR:
return RimVfpDefines::FlowingWaterFractionType::WGR;
default:
return RimVfpDefines::FlowingWaterFractionType::INVALID;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpDefines::FlowingGasFractionType RigVfpTables::getFlowingGasFractionType( const Opm::VFPProdTable& table )
{
switch ( table.getGFRType() )
{
case Opm::VFPProdTable::GFR_TYPE::GFR_GOR:
return RimVfpDefines::FlowingGasFractionType::GOR;
case Opm::VFPProdTable::GFR_TYPE::GFR_GLR:
return RimVfpDefines::FlowingGasFractionType::GLR;
case Opm::VFPProdTable::GFR_TYPE::GFR_OGR:
return RimVfpDefines::FlowingGasFractionType::OGR;
default:
return RimVfpDefines::FlowingGasFractionType::INVALID;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigVfpTables::addInjectionTable( const Opm::VFPInjTable& table )
{
m_injectionTables.push_back( table );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigVfpTables::addProductionTable( const Opm::VFPProdTable& table )
{
m_productionTables.push_back( table );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<int> RigVfpTables::injectionTableNumbers() const
{
std::vector<int> tableNumbers;
for ( const auto& table : m_injectionTables )
{
tableNumbers.push_back( table.getTableNum() );
}
return tableNumbers;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<int> RigVfpTables::productionTableNumbers() const
{
std::vector<int> tableNumbers;
for ( const auto& table : m_productionTables )
{
tableNumbers.push_back( table.getTableNum() );
}
return tableNumbers;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
VfpTableInitialData RigVfpTables::getTableInitialData( int tableIndex ) const
{
auto prodTable = productionTable( tableIndex );
if ( prodTable.has_value() )
{
VfpTableInitialData initialData;
initialData.isProductionTable = true;
initialData.tableNumber = prodTable->getTableNum();
initialData.datumDepth = prodTable->getDatumDepth();
initialData.flowingPhase = getFlowingPhaseType( *prodTable );
initialData.waterFraction = getFlowingWaterFractionType( *prodTable );
initialData.gasFraction = getFlowingGasFractionType( *prodTable );
return initialData;
}
auto injTable = injectionTable( tableIndex );
if ( injTable.has_value() )
{
VfpTableInitialData initialData;
initialData.isProductionTable = false;
initialData.tableNumber = injTable->getTableNum();
initialData.datumDepth = injTable->getDatumDepth();
initialData.flowingPhase = getFlowingPhaseType( *injTable );
return initialData;
}
return {};
}