#13269 Read VFP data without unit conversion

- read VFP data using readers with no unit conversion
- remove existing unit conversion
- make sure correct units are displayed in UI for both Metric and Field
This commit is contained in:
Magne Sjaastad
2025-12-08 15:58:05 +01:00
parent 40078cf8a8
commit 102a9feb32
10 changed files with 229 additions and 311 deletions
@@ -29,13 +29,14 @@
#include "RifVfpInjTable.h"
#include "cafAssert.h"
#include <opm/input/eclipse/Deck/DeckItem.hpp>
#include <opm/input/eclipse/Deck/DeckKeyword.hpp>
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
#include <opm/input/eclipse/Parser/ParserKeywords/V.hpp>
#include <algorithm>
#include <cassert>
#include <cmath>
#include <stdexcept>
@@ -235,8 +236,8 @@ double RifVfpInjTable::operator()( size_t thpIdx, size_t floIdx ) const
size_t nt = m_thpData.size();
size_t nf = m_floData.size();
assert( thpIdx < nt );
assert( floIdx < nf );
CAF_ASSERT( thpIdx < nt );
CAF_ASSERT( floIdx < nf );
size_t index = thpIdx + nt * floIdx;
return m_data[index];
@@ -250,8 +251,8 @@ double& RifVfpInjTable::operator()( size_t thpIdx, size_t floIdx )
size_t nt = m_thpData.size();
size_t nf = m_floData.size();
assert( thpIdx < nt );
assert( floIdx < nf );
CAF_ASSERT( thpIdx < nt );
CAF_ASSERT( floIdx < nf );
size_t index = thpIdx + nt * floIdx;
return m_data[index];
@@ -30,13 +30,14 @@
#include "RifVfpProdTable.h"
#include "RifVfpInjTable.h"
#include "cafAssert.h"
#include <opm/input/eclipse/Deck/DeckItem.hpp>
#include <opm/input/eclipse/Deck/DeckKeyword.hpp>
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
#include <opm/input/eclipse/Parser/ParserKeywords/V.hpp>
#include <algorithm>
#include <cassert>
#include <cmath>
#include <stdexcept>
@@ -337,11 +338,11 @@ double RifVfpProdTable::operator()( size_t thpIdx, size_t wfrIdx, size_t gfrIdx,
size_t na = m_alqData.size();
size_t nf = m_floData.size();
assert( thpIdx < nt );
assert( wfrIdx < nw );
assert( gfrIdx < ng );
assert( alqIdx < na );
assert( floIdx < nf );
CAF_ASSERT( thpIdx < nt );
CAF_ASSERT( wfrIdx < nw );
CAF_ASSERT( gfrIdx < ng );
CAF_ASSERT( alqIdx < na );
CAF_ASSERT( floIdx < nf );
size_t index = thpIdx + nt * ( wfrIdx + nw * ( gfrIdx + ng * ( alqIdx + na * floIdx ) ) );
return m_data[index];
@@ -358,11 +359,11 @@ double& RifVfpProdTable::operator()( size_t thpIdx, size_t wfrIdx, size_t gfrIdx
size_t na = m_alqData.size();
size_t nf = m_floData.size();
assert( thpIdx < nt );
assert( wfrIdx < nw );
assert( gfrIdx < ng );
assert( alqIdx < na );
assert( floIdx < nf );
CAF_ASSERT( thpIdx < nt );
CAF_ASSERT( wfrIdx < nw );
CAF_ASSERT( gfrIdx < ng );
CAF_ASSERT( alqIdx < na );
CAF_ASSERT( floIdx < nf );
size_t index = thpIdx + nt * ( wfrIdx + nw * ( gfrIdx + ng * ( alqIdx + na * floIdx ) ) );
return m_data[index];
@@ -20,6 +20,8 @@
#include "RiaLogging.h"
#include "RiaTextStringTools.h"
#include "FileInterface/RifVfpInjTable.h"
#include "FileInterface/RifVfpProdTable.h"
#include "RifEclipseInputFileTools.h"
#include "cafPdmUiItem.h"
@@ -49,7 +51,7 @@ namespace RiaOpmParserTools
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::pair<Opm::UnitSystem, Opm::VFPInjTable> createInjectionTable( const Opm::DeckKeyword& keyword )
std::pair<Opm::UnitSystem, RifVfpInjTable> createInjectionTable( const Opm::DeckKeyword& keyword )
{
Opm::UnitSystem unitSystem;
{
@@ -63,13 +65,13 @@ std::pair<Opm::UnitSystem, Opm::VFPInjTable> createInjectionTable( const Opm::De
}
}
return { unitSystem, { keyword, unitSystem } };
return { unitSystem, RifVfpInjTable( keyword ) };
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::pair<Opm::UnitSystem, Opm::VFPProdTable> createProductionTable( const Opm::DeckKeyword& keyword )
std::pair<Opm::UnitSystem, RifVfpProdTable> createProductionTable( const Opm::DeckKeyword& keyword )
{
Opm::UnitSystem unitSystem;
{
@@ -85,20 +87,20 @@ std::pair<Opm::UnitSystem, Opm::VFPProdTable> createProductionTable( const Opm::
bool gaslift_opt_active = false;
return { unitSystem, { keyword, gaslift_opt_active, unitSystem } };
return { unitSystem, RifVfpProdTable( keyword, gaslift_opt_active ) };
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::tuple<Opm::UnitSystem, std::vector<Opm::VFPProdTable>, std::vector<Opm::VFPInjTable>>
std::tuple<Opm::UnitSystem, std::vector<RifVfpProdTable>, std::vector<RifVfpInjTable>>
extractVfpTablesFromDataFile( const std::string& dataDeckFilename )
{
if ( !std::filesystem::exists( dataDeckFilename ) )
return std::tuple<Opm::UnitSystem, std::vector<Opm::VFPProdTable>, std::vector<Opm::VFPInjTable>>{};
return std::tuple<Opm::UnitSystem, std::vector<RifVfpProdTable>, std::vector<RifVfpInjTable>>{};
std::vector<Opm::VFPProdTable> prodTables;
std::vector<Opm::VFPInjTable> injTables;
std::vector<RifVfpProdTable> prodTables;
std::vector<RifVfpInjTable> injTables;
std::optional<Opm::UnitSystem> unitSystemFromTables;
@@ -179,7 +181,7 @@ std::tuple<Opm::UnitSystem, std::vector<Opm::VFPProdTable>, std::vector<Opm::VFP
unitSystemValue = *unitSystemFromTables;
}
return std::tuple<Opm::UnitSystem, std::vector<Opm::VFPProdTable>, std::vector<Opm::VFPInjTable>>{ unitSystemValue, prodTables, injTables };
return std::tuple<Opm::UnitSystem, std::vector<RifVfpProdTable>, std::vector<RifVfpInjTable>>{ unitSystemValue, prodTables, injTables };
}
//--------------------------------------------------------------------------------------------------
@@ -25,8 +25,13 @@
#include <string>
#include <vector>
#include "opm/input/eclipse/Schedule/VFPInjTable.hpp"
#include "opm/input/eclipse/Schedule/VFPProdTable.hpp"
namespace Opm
{
class UnitSystem;
}
class RifVfpInjTable;
class RifVfpProdTable;
//--------------------------------------------------------------------------------------------------
///
@@ -34,7 +39,7 @@
namespace RiaOpmParserTools
{
std::tuple<Opm::UnitSystem, std::vector<Opm::VFPProdTable>, std::vector<Opm::VFPInjTable>>
std::tuple<Opm::UnitSystem, std::vector<RifVfpProdTable>, std::vector<RifVfpInjTable>>
extractVfpTablesFromDataFile( const std::string& dataDeckFilename );
std::map<std::string, std::vector<std::pair<int, int>>> extractWseglink( const std::string& filename );
@@ -444,28 +444,26 @@ QString RimCustomVfpPlot::infoForCurve( RimPlotCurve* plotCurve ) const
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( values.waterCutValue )
.arg( getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType::WATER_CUT ) );
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( values.gasLiquidRatioValue )
.arg( getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO ) );
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( values.artificialLiftQuantityValue )
.arg( getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY ) );
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 ) );
info +=
QString( "\nTPH: %1 %2" ).arg( values.thpValue ).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( values.flowRateValue )
.arg( getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType::FLOW_RATE ) );
info += "\n";
@@ -766,10 +764,7 @@ void RimCustomVfpPlot::updateLegendWidget( size_t curveSetCount, CurveNameConten
auto color = curveColors().cycledColor3f( i );
auto formatNamePart = [&]( RimVfpDefines::ProductionVariableType variableType, double selectionValue, const QString& namePart ) -> QString
{
double displayValue = convertToDisplayUnit( selectionValue, variableType );
return QString( " %1:%2" ).arg( namePart ).arg( displayValue );
};
{ return QString( " %1:%2" ).arg( namePart ).arg( selectionValue ); };
if ( plotCurveIdx < m_plotCurveMetaData.size() )
{
@@ -843,9 +838,8 @@ void RimCustomVfpPlot::populatePlotWidgetWithPlotData( RiuPlotWidget*
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 );
double value = ( variableType == m_familyVariable() ) ? familyValue : selectionValue;
return QString( " %1:%2" ).arg( namePart ).arg( value );
};
for ( auto curveIndex = 0u; curveIndex < plotData.size(); curveIndex++ )
@@ -917,27 +911,6 @@ void RimCustomVfpPlot::populatePlotWidgetWithPlotData( RiuPlotWidget*
updateConnectedEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimCustomVfpPlot::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;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -1190,35 +1163,25 @@ void RimCustomVfpPlot::initializeFromInitData( const VfpTableInitialData& table
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimCustomVfpPlot::convertToDisplayUnit( double value, RimVfpDefines::ProductionVariableType variableType )
QString RimCustomVfpPlot::getDisplayUnit( RimVfpDefines::ProductionVariableType variableType ) const
{
if ( variableType == RimVfpDefines::ProductionVariableType::THP )
// Use RigVfpTables to get proper unit strings based on the actual unit system
if ( m_mainDataSource && m_mainDataSource->dataSource() && m_mainDataSource->dataSource()->vfpTables() )
{
return RiaEclipseUnitTools::pascalToBar( value );
auto vfpTables = m_mainDataSource->dataSource()->vfpTables();
// Use the static method from RigVfpTables that properly handles unit systems
return RigVfpTables::getDisplayUnit( variableType, vfpTables->unitSystem() );
}
if ( variableType == RimVfpDefines::ProductionVariableType::FLOW_RATE )
{
// Convert to m3/sec to m3/day
return value * static_cast<double>( 24 * 60 * 60 );
}
return value;
// Return empty string if VFP data not available
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimCustomVfpPlot::convertToDisplayUnit( std::vector<double>& values, RimVfpDefines::ProductionVariableType variableType )
{
for ( double& value : values )
value = convertToDisplayUnit( value, variableType );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimCustomVfpPlot::getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType variableType )
QString RimCustomVfpPlot::getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType variableType ) const
{
QString unit = getDisplayUnit( variableType );
if ( !unit.isEmpty() ) return QString( "[%1]" ).arg( unit );
@@ -1226,19 +1189,6 @@ QString RimCustomVfpPlot::getDisplayUnitWithBracket( RimVfpDefines::ProductionVa
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimCustomVfpPlot::getDisplayUnit( RimVfpDefines::ProductionVariableType variableType )
{
if ( variableType == RimVfpDefines::ProductionVariableType::THP ) return "Bar";
if ( variableType == RimVfpDefines::ProductionVariableType::FLOW_RATE ) return "Sm3/day";
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -1424,9 +1374,7 @@ void RimCustomVfpPlot::calculateTableValueOptions( RimVfpDefines::ProductionVari
for ( double value : values )
{
options.push_back(
caf::PdmOptionItemInfo( QString( "%1 %2" ).arg( convertToDisplayUnit( value, variableType ) ).arg( getDisplayUnit( variableType ) ),
value ) );
options.push_back( caf::PdmOptionItemInfo( QString( "%1 %2" ).arg( value ).arg( getDisplayUnit( variableType ) ), value ) );
}
}
@@ -123,10 +123,8 @@ private:
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable );
static double convertToDisplayUnit( double value, RimVfpDefines::ProductionVariableType variableType );
static void convertToDisplayUnit( std::vector<double>& values, RimVfpDefines::ProductionVariableType variableType );
static QString getDisplayUnit( RimVfpDefines::ProductionVariableType variableType );
static QString getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType variableType );
QString getDisplayUnit( RimVfpDefines::ProductionVariableType variableType ) const;
QString getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType variableType ) const;
struct CurveNameContent
{
@@ -148,8 +146,6 @@ private:
void updateLegendWidget( size_t curveSetCount, CurveNameContent& curveNameContent );
static QString axisTitle( RimVfpDefines::ProductionVariableType variableType, RimVfpDefines::FlowingPhaseType flowingPhase );
void connectAxisSignals( RimPlotAxisProperties* axis );
void axisSettingsChanged( const caf::SignalEmitter* emitter );
void axisLogarithmicChanged( const caf::SignalEmitter* emitter, bool isLogarithmic );
@@ -20,12 +20,13 @@
#include "RiaOpmParserTools.h"
#include "RifVfpInjTable.h"
#include "RifVfpProdTable.h"
#include "RigVfpTables.h"
#include "RimVfpTable.h"
#include <opm/input/eclipse/Units/UnitSystem.hpp>
#include "cafCmdFeatureMenuBuilder.h"
#include <QFileInfo>
@@ -87,7 +88,7 @@ void RimVfpTableData::ensureDataIsImported()
auto table = new RimVfpTable;
table->setDataSource( this );
table->setTableNumber( prod.getTableNum() );
table->setTableNumber( prod.tableNum() );
table->setTableType( RimVfpDefines::TableType::PRODUCTION );
m_tables.push_back( table );
}
@@ -98,7 +99,7 @@ void RimVfpTableData::ensureDataIsImported()
auto table = new RimVfpTable;
table->setDataSource( this );
table->setTableNumber( inj.getTableNum() );
table->setTableNumber( inj.tableNum() );
table->setTableType( RimVfpDefines::TableType::INJECTION );
m_tables.push_back( table );
}
@@ -22,13 +22,13 @@
#include "cafAppEnum.h"
#include "opm/input/eclipse/Schedule/VFPInjTable.hpp"
#include "opm/input/eclipse/Schedule/VFPProdTable.hpp"
#include "FileInterface/RifVfpInjTable.h"
#include "FileInterface/RifVfpProdTable.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
VfpPlotData RigVfpTables::populatePlotData( const Opm::VFPInjTable& table,
VfpPlotData RigVfpTables::populatePlotData( const RifVfpInjTable& table,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase ) const
{
@@ -41,12 +41,12 @@ VfpPlotData RigVfpTables::populatePlotData( const Opm::VFPInjTable&
getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType::THP ) );
plotData.setYAxisTitle( yAxisTitle );
std::vector<double> thpValues = table.getTHPAxis();
std::vector<double> thpValues = table.thpAxis();
for ( size_t thp = 0; thp < thpValues.size(); thp++ )
{
size_t numValues = table.getFloAxis().size();
std::vector<double> xVals = table.getFloAxis();
size_t numValues = table.floAxis().size();
std::vector<double> xVals = table.floAxis();
std::vector<double> yVals( numValues, 0.0 );
for ( size_t y = 0; y < numValues; y++ )
{
@@ -57,16 +57,13 @@ VfpPlotData RigVfpTables::populatePlotData( const Opm::VFPInjTable&
}
}
double value = convertToDisplayUnit( thpValues[thp], RimVfpDefines::ProductionVariableType::THP );
double value = thpValues[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 );
}
@@ -76,7 +73,7 @@ VfpPlotData RigVfpTables::populatePlotData( const Opm::VFPInjTable&
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
VfpPlotData RigVfpTables::populatePlotData( const Opm::VFPProdTable& table,
VfpPlotData RigVfpTables::populatePlotData( const RifVfpProdTable& table,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
@@ -132,22 +129,27 @@ VfpPlotData RigVfpTables::populatePlotData( const Opm::VFPProdTable&
}
}
double familyValue = convertToDisplayUnit( familyVariableValues[familyIdx], familyVariable );
double familyValue = familyVariableValues[familyIdx];
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;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const Opm::UnitSystem RigVfpTables::unitSystem() const
{
return m_unitSystem;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -201,7 +203,7 @@ VfpPlotData RigVfpTables::populatePlotData( int
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
VfpPlotData RigVfpTables::populatePlotData( const Opm::VFPProdTable& table,
VfpPlotData RigVfpTables::populatePlotData( const RifVfpProdTable& table,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
@@ -281,16 +283,13 @@ VfpPlotData RigVfpTables::populatePlotData( const Opm::VFPProdTable&
}
}
double familyValue = convertToDisplayUnit( currentFamilyValue, familyVariable );
double familyValue = currentFamilyValue;
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 );
}
@@ -476,64 +475,6 @@ QString RigVfpTables::getDisplayUnitWithBracket( RimVfpDefines::ProductionVariab
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RigVfpTables::convertToDisplayUnit( double value, RimVfpDefines::ProductionVariableType variableType ) const
{
return convertToDisplayUnit( value, variableType, m_unitSystem );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RigVfpTables::convertToDisplayUnit( double value, RimVfpDefines::ProductionVariableType variableType, const Opm::UnitSystem& unitSystem )
{
bool isFieldUnits = ( unitSystem.getType() == Opm::UnitSystem::UnitType::UNIT_TYPE_FIELD );
if ( variableType == RimVfpDefines::ProductionVariableType::THP )
{
if ( isFieldUnits )
{
// Convert from psi (field) to psia - no conversion needed, already in correct units
return value;
}
else
{
// Convert Pascal (SI) to Bar (metric)
return RiaEclipseUnitTools::pascalToBar( value );
}
}
if ( variableType == RimVfpDefines::ProductionVariableType::FLOW_RATE )
{
// Convert from per-second to per-day for both unit systems
const double secToDay = 24.0 * 60.0 * 60.0;
return value * secToDay;
}
return value;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigVfpTables::convertToDisplayUnit( std::vector<double>& values, RimVfpDefines::ProductionVariableType variableType ) const
{
convertToDisplayUnit( values, variableType, m_unitSystem );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigVfpTables::convertToDisplayUnit( std::vector<double>& values,
RimVfpDefines::ProductionVariableType variableType,
const Opm::UnitSystem& unitSystem )
{
for ( double& value : values )
value = convertToDisplayUnit( value, variableType, unitSystem );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -582,38 +523,28 @@ QString RigVfpTables::textForPlotData( const VfpPlotData& plotData )
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RigVfpTables::getProductionTableData( const Opm::VFPProdTable& table, RimVfpDefines::ProductionVariableType variableType ) const
std::vector<double> RigVfpTables::getProductionTableData( const RifVfpProdTable& table, RimVfpDefines::ProductionVariableType variableType ) const
{
std::vector<double> xVals;
if ( variableType == RimVfpDefines::ProductionVariableType::WATER_CUT )
{
xVals = table.getWFRAxis();
xVals = table.wfrAxis();
}
else if ( variableType == RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO )
{
xVals = table.getGFRAxis();
xVals = table.gfrAxis();
}
else if ( variableType == RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY )
{
xVals = table.getALQAxis();
// Convert ALQ values to raw values. No conversion of this data type is done in convertToDisplayUnit. As convertToDisplayUnit is a
// static function, it will require a lot of refactoring to get the unit system information communicated to this function.
auto alq_dim = Opm::VFPProdTable::ALQDimension( table.getALQType(), m_unitSystem );
for ( double& value : xVals )
{
value = alq_dim.convertSiToRaw( value );
}
xVals = table.alqAxis();
}
else if ( variableType == RimVfpDefines::ProductionVariableType::FLOW_RATE )
{
// Values are converted in convertToDisplayUnit
xVals = table.getFloAxis();
xVals = table.floAxis();
}
else if ( variableType == RimVfpDefines::ProductionVariableType::THP )
{
// Values are converted in convertToDisplayUnit
xVals = table.getTHPAxis();
xVals = table.thpAxis();
}
return xVals;
@@ -636,7 +567,7 @@ std::vector<double> RigVfpTables::getProductionTableData( int tableIndex, RimVfp
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RigVfpTables::getVariableIndex( const Opm::VFPProdTable& table,
size_t RigVfpTables::getVariableIndex( const RifVfpProdTable& table,
RimVfpDefines::ProductionVariableType targetVariable,
RimVfpDefines::ProductionVariableType primaryVariable,
size_t primaryValue,
@@ -659,7 +590,7 @@ size_t RigVfpTables::getVariableIndex( const Opm::VFPProdTable& tab
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RigVfpTables::getVariableIndexForValue( const Opm::VFPProdTable& table,
size_t RigVfpTables::getVariableIndexForValue( const RifVfpProdTable& table,
RimVfpDefines::ProductionVariableType targetVariable,
RimVfpDefines::ProductionVariableType primaryVariable,
double primaryValue,
@@ -705,7 +636,7 @@ size_t RigVfpTables::getVariableIndexForValue( const Opm::VFPProdTable&
}
auto findClosestIndexForVariable =
[&]( RimVfpDefines::ProductionVariableType targetVariable, const double selectedValue, const Opm::VFPProdTable& table )
[&]( RimVfpDefines::ProductionVariableType targetVariable, const double selectedValue, const RifVfpProdTable& table )
{
const auto values = getProductionTableData( table, targetVariable );
return findClosestIndex( values, selectedValue );
@@ -743,11 +674,11 @@ size_t RigVfpTables::getVariableIndexForValue( const Opm::VFPProdTable&
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::optional<Opm::VFPInjTable> RigVfpTables::injectionTable( int tableNumber ) const
std::optional<RifVfpInjTable> RigVfpTables::injectionTable( int tableNumber ) const
{
for ( const auto& table : m_injectionTables )
{
if ( table.getTableNum() == tableNumber )
if ( table.tableNum() == tableNumber )
{
return table;
}
@@ -759,11 +690,11 @@ std::optional<Opm::VFPInjTable> RigVfpTables::injectionTable( int tableNumber )
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::optional<Opm::VFPProdTable> RigVfpTables::productionTable( int tableNumber ) const
std::optional<RifVfpProdTable> RigVfpTables::productionTable( int tableNumber ) const
{
for ( const auto& table : m_productionTables )
{
if ( table.getTableNum() == tableNumber )
if ( table.tableNum() == tableNumber )
{
return table;
}
@@ -775,15 +706,15 @@ std::optional<Opm::VFPProdTable> RigVfpTables::productionTable( int tableNumber
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpDefines::FlowingPhaseType RigVfpTables::getFlowingPhaseType( const Opm::VFPProdTable& table )
RimVfpDefines::FlowingPhaseType RigVfpTables::getFlowingPhaseType( const RifVfpProdTable& table )
{
switch ( table.getFloType() )
switch ( table.floType() )
{
case Opm::VFPProdTable::FLO_TYPE::FLO_OIL:
case RifVfpProdTable::FLO_TYPE::FLO_OIL:
return RimVfpDefines::FlowingPhaseType::OIL;
case Opm::VFPProdTable::FLO_TYPE::FLO_GAS:
case RifVfpProdTable::FLO_TYPE::FLO_GAS:
return RimVfpDefines::FlowingPhaseType::GAS;
case Opm::VFPProdTable::FLO_TYPE::FLO_LIQ:
case RifVfpProdTable::FLO_TYPE::FLO_LIQ:
return RimVfpDefines::FlowingPhaseType::LIQUID;
default:
return RimVfpDefines::FlowingPhaseType::INVALID;
@@ -793,15 +724,15 @@ RimVfpDefines::FlowingPhaseType RigVfpTables::getFlowingPhaseType( const Opm::VF
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpDefines::FlowingPhaseType RigVfpTables::getFlowingPhaseType( const Opm::VFPInjTable& table )
RimVfpDefines::FlowingPhaseType RigVfpTables::getFlowingPhaseType( const RifVfpInjTable& table )
{
switch ( table.getFloType() )
switch ( table.floType() )
{
case Opm::VFPInjTable::FLO_TYPE::FLO_OIL:
case RifVfpInjTable::FLO_TYPE::FLO_OIL:
return RimVfpDefines::FlowingPhaseType::OIL;
case Opm::VFPInjTable::FLO_TYPE::FLO_GAS:
case RifVfpInjTable::FLO_TYPE::FLO_GAS:
return RimVfpDefines::FlowingPhaseType::GAS;
case Opm::VFPInjTable::FLO_TYPE::FLO_WAT:
case RifVfpInjTable::FLO_TYPE::FLO_WAT:
return RimVfpDefines::FlowingPhaseType::WATER;
default:
return RimVfpDefines::FlowingPhaseType::INVALID;
@@ -811,15 +742,15 @@ RimVfpDefines::FlowingPhaseType RigVfpTables::getFlowingPhaseType( const Opm::VF
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpDefines::FlowingWaterFractionType RigVfpTables::getFlowingWaterFractionType( const Opm::VFPProdTable& table )
RimVfpDefines::FlowingWaterFractionType RigVfpTables::getFlowingWaterFractionType( const RifVfpProdTable& table )
{
switch ( table.getWFRType() )
switch ( table.wfrType() )
{
case Opm::VFPProdTable::WFR_TYPE::WFR_WOR:
case RifVfpProdTable::WFR_TYPE::WFR_WOR:
return RimVfpDefines::FlowingWaterFractionType::WOR;
case Opm::VFPProdTable::WFR_TYPE::WFR_WCT:
case RifVfpProdTable::WFR_TYPE::WFR_WCT:
return RimVfpDefines::FlowingWaterFractionType::WCT;
case Opm::VFPProdTable::WFR_TYPE::WFR_WGR:
case RifVfpProdTable::WFR_TYPE::WFR_WGR:
return RimVfpDefines::FlowingWaterFractionType::WGR;
default:
return RimVfpDefines::FlowingWaterFractionType::INVALID;
@@ -829,15 +760,15 @@ RimVfpDefines::FlowingWaterFractionType RigVfpTables::getFlowingWaterFractionTyp
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpDefines::FlowingGasFractionType RigVfpTables::getFlowingGasFractionType( const Opm::VFPProdTable& table )
RimVfpDefines::FlowingGasFractionType RigVfpTables::getFlowingGasFractionType( const RifVfpProdTable& table )
{
switch ( table.getGFRType() )
switch ( table.gfrType() )
{
case Opm::VFPProdTable::GFR_TYPE::GFR_GOR:
case RifVfpProdTable::GFR_TYPE::GFR_GOR:
return RimVfpDefines::FlowingGasFractionType::GOR;
case Opm::VFPProdTable::GFR_TYPE::GFR_GLR:
case RifVfpProdTable::GFR_TYPE::GFR_GLR:
return RimVfpDefines::FlowingGasFractionType::GLR;
case Opm::VFPProdTable::GFR_TYPE::GFR_OGR:
case RifVfpProdTable::GFR_TYPE::GFR_OGR:
return RimVfpDefines::FlowingGasFractionType::OGR;
default:
return RimVfpDefines::FlowingGasFractionType::INVALID;
@@ -855,7 +786,7 @@ void RigVfpTables::setUnitSystem( const Opm::UnitSystem& unitSystem )
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigVfpTables::addInjectionTable( const Opm::VFPInjTable& table )
void RigVfpTables::addInjectionTable( const RifVfpInjTable& table )
{
m_injectionTables.push_back( table );
}
@@ -863,7 +794,7 @@ void RigVfpTables::addInjectionTable( const Opm::VFPInjTable& table )
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigVfpTables::addProductionTable( const Opm::VFPProdTable& table )
void RigVfpTables::addProductionTable( const RifVfpProdTable& table )
{
m_productionTables.push_back( table );
}
@@ -877,7 +808,7 @@ std::vector<int> RigVfpTables::injectionTableNumbers() const
for ( const auto& table : m_injectionTables )
{
tableNumbers.push_back( table.getTableNum() );
tableNumbers.push_back( table.tableNum() );
}
return tableNumbers;
@@ -892,7 +823,7 @@ std::vector<int> RigVfpTables::productionTableNumbers() const
for ( const auto& table : m_productionTables )
{
tableNumbers.push_back( table.getTableNum() );
tableNumbers.push_back( table.tableNum() );
}
return tableNumbers;
@@ -908,8 +839,8 @@ VfpTableInitialData RigVfpTables::getTableInitialData( int tableIndex ) const
{
VfpTableInitialData initialData{};
initialData.isProductionTable = true;
initialData.tableNumber = prodTable->getTableNum();
initialData.datumDepth = prodTable->getDatumDepth();
initialData.tableNumber = prodTable->tableNum();
initialData.datumDepth = prodTable->datumDepth();
initialData.flowingPhase = getFlowingPhaseType( *prodTable );
initialData.waterFraction = getFlowingWaterFractionType( *prodTable );
initialData.gasFraction = getFlowingGasFractionType( *prodTable );
@@ -922,8 +853,8 @@ VfpTableInitialData RigVfpTables::getTableInitialData( int tableIndex ) const
{
VfpTableInitialData initialData{};
initialData.isProductionTable = false;
initialData.tableNumber = injTable->getTableNum();
initialData.datumDepth = injTable->getDatumDepth();
initialData.tableNumber = injTable->tableNum();
initialData.datumDepth = injTable->datumDepth();
initialData.flowingPhase = getFlowingPhaseType( *injTable );
return initialData;
}
@@ -29,10 +29,12 @@
namespace Opm
{
class VFPInjTable;
class VFPProdTable;
class UnitSystem;
} // namespace Opm
class RifVfpInjTable;
class RifVfpProdTable;
class VfpPlotData
{
public:
@@ -102,9 +104,11 @@ struct VfpTableInitialData
class RigVfpTables
{
public:
void setUnitSystem( const Opm::UnitSystem& unitSystem );
void addInjectionTable( const Opm::VFPInjTable& table );
void addProductionTable( const Opm::VFPProdTable& table );
void setUnitSystem( const Opm::UnitSystem& unitSystem );
const Opm::UnitSystem unitSystem() const;
void addInjectionTable( const RifVfpInjTable& table );
void addProductionTable( const RifVfpProdTable& table );
std::vector<int> injectionTableNumbers() const;
std::vector<int> productionTableNumbers() const;
@@ -141,24 +145,20 @@ public:
// Static versions of display and conversion functions that take unit system parameter
static QString getDisplayUnit( RimVfpDefines::ProductionVariableType variableType, const Opm::UnitSystem& unitSystem );
static QString getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType variableType, const Opm::UnitSystem& unitSystem );
static double convertToDisplayUnit( double value, RimVfpDefines::ProductionVariableType variableType, const Opm::UnitSystem& unitSystem );
static void convertToDisplayUnit( std::vector<double>& values,
RimVfpDefines::ProductionVariableType variableType,
const Opm::UnitSystem& unitSystem );
private:
VfpPlotData populatePlotData( const Opm::VFPInjTable& table,
VfpPlotData populatePlotData( const RifVfpInjTable& table,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase ) const;
VfpPlotData populatePlotData( const Opm::VFPProdTable& table,
VfpPlotData populatePlotData( const RifVfpProdTable& table,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase,
const VfpTableSelection& tableSelection ) const;
VfpPlotData populatePlotData( const Opm::VFPProdTable& table,
VfpPlotData populatePlotData( const RifVfpProdTable& table,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
@@ -168,13 +168,11 @@ private:
QString axisTitle( RimVfpDefines::ProductionVariableType variableType, RimVfpDefines::FlowingPhaseType flowingPhase ) const;
QString getDisplayUnit( RimVfpDefines::ProductionVariableType variableType ) const;
QString getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType variableType ) const;
double convertToDisplayUnit( double value, RimVfpDefines::ProductionVariableType variableType ) const;
void convertToDisplayUnit( std::vector<double>& values, RimVfpDefines::ProductionVariableType variableType ) const;
static QString textForPlotData( const VfpPlotData& plotData );
std::vector<double> getProductionTableData( const Opm::VFPProdTable& table, RimVfpDefines::ProductionVariableType variableType ) const;
size_t getVariableIndex( const Opm::VFPProdTable& table,
std::vector<double> getProductionTableData( const RifVfpProdTable& table, RimVfpDefines::ProductionVariableType variableType ) const;
size_t getVariableIndex( const RifVfpProdTable& table,
RimVfpDefines::ProductionVariableType targetVariable,
RimVfpDefines::ProductionVariableType primaryVariable,
size_t primaryValue,
@@ -182,7 +180,7 @@ private:
size_t familyValue,
const VfpTableSelection& tableSelection ) const;
size_t getVariableIndexForValue( const Opm::VFPProdTable& table,
size_t getVariableIndexForValue( const RifVfpProdTable& table,
RimVfpDefines::ProductionVariableType targetVariable,
RimVfpDefines::ProductionVariableType primaryVariable,
double primaryValue,
@@ -190,19 +188,19 @@ private:
double familyValue,
const VfpValueSelection& valueSelection ) const;
std::optional<Opm::VFPInjTable> injectionTable( int tableNumber ) const;
std::optional<Opm::VFPProdTable> productionTable( int tableNumber ) const;
std::optional<RifVfpInjTable> injectionTable( int tableNumber ) const;
std::optional<RifVfpProdTable> productionTable( int tableNumber ) const;
static RimVfpDefines::FlowingPhaseType getFlowingPhaseType( const Opm::VFPProdTable& table );
static RimVfpDefines::FlowingPhaseType getFlowingPhaseType( const Opm::VFPInjTable& table );
static RimVfpDefines::FlowingWaterFractionType getFlowingWaterFractionType( const Opm::VFPProdTable& table );
static RimVfpDefines::FlowingGasFractionType getFlowingGasFractionType( const Opm::VFPProdTable& table );
static RimVfpDefines::FlowingPhaseType getFlowingPhaseType( const RifVfpProdTable& table );
static RimVfpDefines::FlowingPhaseType getFlowingPhaseType( const RifVfpInjTable& table );
static RimVfpDefines::FlowingWaterFractionType getFlowingWaterFractionType( const RifVfpProdTable& table );
static RimVfpDefines::FlowingGasFractionType getFlowingGasFractionType( const RifVfpProdTable& table );
// Returns the indices of the closest values in valuesToMatch for each value in sourceValues. Returned index value -1 indicates no match.
static std::vector<int> findClosestIndices( const std::vector<double>& sourceValues, const std::vector<double>& valuesToMatch );
private:
std::vector<Opm::VFPInjTable> m_injectionTables;
std::vector<Opm::VFPProdTable> m_productionTables;
Opm::UnitSystem m_unitSystem;
std::vector<RifVfpInjTable> m_injectionTables;
std::vector<RifVfpProdTable> m_productionTables;
Opm::UnitSystem m_unitSystem;
};
@@ -21,8 +21,14 @@
#include "ProjectDataModel/VerticalFlowPerformance/RimVfpDefines.h"
#include "RigVfpTables.h"
#include "FileInterface/RifVfpInjTable.h"
#include "FileInterface/RifVfpProdTable.h"
#include "ProjectDataModel/RiaOpmParserTools.h"
#include "opm/input/eclipse/Units/UnitSystem.hpp"
#include "RiaTestDataDirectory.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -130,55 +136,84 @@ TEST( RigVfpTables, MetricUnitDisplayUnits )
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RigVfpTables, FieldUnitConversion )
TEST( RigVfpTables, ImportVfpDataFromFile )
{
// Test field unit conversions
Opm::UnitSystem fieldUnitSystem = Opm::UnitSystem::newFIELD();
// Import VFP data using the new ResInsight VFP file readers
std::string vfpFilePath = QString( "%1/RigSimulationInputTool/model5/include/flowl_b_vfp.ecl" ).arg( TEST_DATA_DIR ).toStdString();
// Test THP conversion for field units (no conversion should be done, data already in psi)
double thpValue = 100.0; // psi
double convertedThp = RigVfpTables::convertToDisplayUnit( thpValue, RimVfpDefines::ProductionVariableType::THP, fieldUnitSystem );
EXPECT_DOUBLE_EQ( 100.0, convertedThp ); // Should remain unchanged
auto [unitSystem, prodTables, injTables] = RiaOpmParserTools::extractVfpTablesFromDataFile( vfpFilePath );
// Test flow rate conversion for field units (convert from stb/sec to stb/day)
double flowRateValue = 1.0; // stb/sec
double convertedFlowRate =
RigVfpTables::convertToDisplayUnit( flowRateValue, RimVfpDefines::ProductionVariableType::FLOW_RATE, fieldUnitSystem );
EXPECT_DOUBLE_EQ( 86400.0, convertedFlowRate ); // 1 * 24 * 60 * 60 = 86400 stb/day
// Verify we got data
EXPECT_FALSE( prodTables.empty() );
EXPECT_TRUE( injTables.empty() ); // This file contains only production tables
// Test vector conversion
std::vector<double> flowRateValues = { 1.0, 2.0, 0.5 }; // stb/sec
RigVfpTables::convertToDisplayUnit( flowRateValues, RimVfpDefines::ProductionVariableType::FLOW_RATE, fieldUnitSystem );
// Check unit system is metric (based on VFPPROD header "METRIC")
EXPECT_EQ( Opm::UnitSystem::UnitType::UNIT_TYPE_METRIC, unitSystem.getType() );
EXPECT_DOUBLE_EQ( 86400.0, flowRateValues[0] ); // 86400 stb/day
EXPECT_DOUBLE_EQ( 172800.0, flowRateValues[1] ); // 172800 stb/day
EXPECT_DOUBLE_EQ( 43200.0, flowRateValues[2] ); // 43200 stb/day
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RigVfpTables, MetricUnitConversion )
{
// Test metric unit conversions
Opm::UnitSystem metricUnitSystem = Opm::UnitSystem::newMETRIC();
// Test THP conversion for metric units (Pascal to Bar)
double thpValue = 100000.0; // Pascal
double convertedThp = RigVfpTables::convertToDisplayUnit( thpValue, RimVfpDefines::ProductionVariableType::THP, metricUnitSystem );
EXPECT_DOUBLE_EQ( 1.0, convertedThp ); // 100000 Pa = 1 Bar
// Test flow rate conversion for metric units (m3/sec to m3/day)
double flowRateValue = 1.0; // m3/sec
double convertedFlowRate =
RigVfpTables::convertToDisplayUnit( flowRateValue, RimVfpDefines::ProductionVariableType::FLOW_RATE, metricUnitSystem );
EXPECT_DOUBLE_EQ( 86400.0, convertedFlowRate ); // 1 * 24 * 60 * 60 = 86400 m3/day
// Test vector conversion
std::vector<double> thpValues = { 100000.0, 200000.0, 50000.0 }; // Pascal
RigVfpTables::convertToDisplayUnit( thpValues, RimVfpDefines::ProductionVariableType::THP, metricUnitSystem );
EXPECT_DOUBLE_EQ( 1.0, thpValues[0] ); // 1 Bar
EXPECT_DOUBLE_EQ( 2.0, thpValues[1] ); // 2 Bar
EXPECT_DOUBLE_EQ( 0.5, thpValues[2] ); // 0.5 Bar
// Verify first production table
const auto& table = prodTables[0];
EXPECT_EQ( 4, table.tableNum() );
EXPECT_DOUBLE_EQ( 114.60, table.datumDepth() );
// Check table type indicators
EXPECT_EQ( RifVfpProdTable::FLO_TYPE::FLO_LIQ, table.floType() );
EXPECT_EQ( RifVfpProdTable::WFR_TYPE::WFR_WCT, table.wfrType() );
EXPECT_EQ( RifVfpProdTable::GFR_TYPE::GFR_GOR, table.gfrType() );
EXPECT_EQ( RifVfpProdTable::ALQ_TYPE::ALQ_GRAT, table.alqType() );
// Verify axis data preserved from original file
const auto& floAxis = table.floAxis();
EXPECT_EQ( 19, floAxis.size() );
EXPECT_DOUBLE_EQ( 20.0, floAxis[0] );
EXPECT_DOUBLE_EQ( 30.0, floAxis[1] );
EXPECT_DOUBLE_EQ( 11171.0, floAxis[floAxis.size() - 1] );
const auto& thpAxis = table.thpAxis();
EXPECT_EQ( 6, thpAxis.size() );
EXPECT_DOUBLE_EQ( 2.00, thpAxis[0] );
EXPECT_DOUBLE_EQ( 35.00, thpAxis[thpAxis.size() - 1] );
const auto& wfrAxis = table.wfrAxis();
EXPECT_EQ( 10, wfrAxis.size() );
EXPECT_DOUBLE_EQ( 0.000, wfrAxis[0] );
EXPECT_DOUBLE_EQ( 0.990, wfrAxis[wfrAxis.size() - 1] );
const auto& gfrAxis = table.gfrAxis();
EXPECT_EQ( 9, gfrAxis.size() );
EXPECT_DOUBLE_EQ( 20.0, gfrAxis[0] );
EXPECT_DOUBLE_EQ( 1000.0, gfrAxis[gfrAxis.size() - 1] );
const auto& alqAxis = table.alqAxis();
EXPECT_EQ( 6, alqAxis.size() );
EXPECT_DOUBLE_EQ( 0.0, alqAxis[0] );
EXPECT_DOUBLE_EQ( 300000.0, alqAxis[alqAxis.size() - 1] );
// Test table dimensions
auto shape = table.shape();
EXPECT_EQ( 6, shape[0] ); // THP
EXPECT_EQ( 10, shape[1] ); // WFR
EXPECT_EQ( 9, shape[2] ); // GFR
EXPECT_EQ( 6, shape[3] ); // ALQ
EXPECT_EQ( 19, shape[4] ); // FLO
// Test specific table value (first data point from file)
// THP=1, WFR=1, GFR=1, ALQ=1 should give BHP=13.977
EXPECT_DOUBLE_EQ( 13.977, table( 0, 0, 0, 0, 0 ) );
// Test RigVfpTables functionality with imported data
RigVfpTables vfpTables;
vfpTables.setUnitSystem( unitSystem );
vfpTables.addProductionTable( table );
// Verify table numbers
auto tableNumbers = vfpTables.productionTableNumbers();
EXPECT_EQ( 1, tableNumbers.size() );
EXPECT_EQ( 4, tableNumbers[0] );
// Test unit display with imported data
QString thpUnit = RigVfpTables::getDisplayUnit( RimVfpDefines::ProductionVariableType::THP, vfpTables.unitSystem() );
EXPECT_EQ( "Bar", thpUnit.toStdString() );
QString flowRateUnit = RigVfpTables::getDisplayUnit( RimVfpDefines::ProductionVariableType::FLOW_RATE, vfpTables.unitSystem() );
EXPECT_EQ( "Sm3/day", flowRateUnit.toStdString() );
}