Parse and display VFPPROD tables.

This commit is contained in:
Kristian Bendiksen 2020-04-20 22:48:45 +02:00 committed by Magne Sjaastad
parent 1b9a674213
commit eea9e88bfe
4 changed files with 221 additions and 28 deletions

View File

@ -48,8 +48,6 @@
#include <QFileInfo>
#include "opm/parser/eclipse/EclipseState/Schedule/VFPInjTable.hpp"
//==================================================================================================
//
//
@ -58,6 +56,27 @@
CAF_PDM_SOURCE_INIT( RimVfpPlot, "VfpPlot" );
namespace caf
{
template <>
void caf::AppEnum<RimVfpPlot::TableType>::setUp()
{
addItem( RimVfpPlot::TableType::INJECTION, "INJECTION", "Injection" );
addItem( RimVfpPlot::TableType::PRODUCTION, "PRODUCTION", "Production" );
setDefault( RimVfpPlot::TableType::INJECTION );
}
template <>
void caf::AppEnum<RimVfpPlot::ProductionTableType>::setUp()
{
addItem( RimVfpPlot::ProductionTableType::LIQUID_FLOW_RATE, "LIQUID_FLOW_RATE", "Liquid Flow Rate" );
addItem( RimVfpPlot::ProductionTableType::ARTIFICIAL_LIFT_QUANTITY, "ALQ", "Artificial Lift Quantity" );
addItem( RimVfpPlot::ProductionTableType::WATER_CUT, "WATER_CUT", "Water Cut" );
addItem( RimVfpPlot::ProductionTableType::GAS_LIQUID_RATIO, "GAS_LIQUID_RATIO", "Gas Liquid Ratio" );
setDefault( RimVfpPlot::ProductionTableType::LIQUID_FLOW_RATE );
}
} // namespace caf
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -69,6 +88,19 @@ RimVfpPlot::RimVfpPlot()
CAF_PDM_InitFieldNoDefault( &m_case, "Case", "Case", "", "", "" );
CAF_PDM_InitField( &m_wellName, "WellName", QString( "None" ), "Well", "", "", "" );
caf::AppEnum<RimVfpPlot::TableType> defaultTableType = RimVfpPlot::TableType::INJECTION;
CAF_PDM_InitField( &m_tableType, "TableType", defaultTableType, "Table Type", "", "", "" );
caf::AppEnum<RimVfpPlot::ProductionTableType> defaultProductionTableType =
RimVfpPlot::ProductionTableType::LIQUID_FLOW_RATE;
CAF_PDM_InitField( &m_productionTableType,
"ProductionTableType",
defaultProductionTableType,
"Production Table Type",
"",
"",
"" );
m_showWindow = false;
m_showPlotLegends = true;
@ -325,41 +357,55 @@ void RimVfpPlot::onLoadDataAndUpdate()
updateLegend();
QString phaseString = "N/A";
bool isInjector = m_tableType == RimVfpPlot::TableType::INJECTION;
if ( m_case && m_case->ensureReservoirCaseIsOpen() )
{
// TODO: extract data from data file
//
std::set<std::string> wells = {"F2H", "C1H", "C2H", "C3H", "C4AH", "C4H", "F1H", "F3H", "F4H"};
std::string strippedWellName = QString( m_wellName() ).remove( "-" ).toStdString();
if ( wells.find( strippedWellName ) != wells.end() )
if ( isInjector )
{
QString gridFileName = m_case->gridFileName();
std::cout << "Grid file name: " << gridFileName.toStdString() << std::endl;
QFileInfo fi( gridFileName );
std::set<std::string> wells = {"F2H", "C1H", "C2H", "C3H", "C4AH", "C4H", "F1H", "F3H", "F4H"};
std::string strippedWellName = QString( m_wellName() ).remove( "-" ).toStdString();
std::string filename = fi.canonicalPath().toStdString() + "/INCLUDE/VFP/" + strippedWellName + ".Ecl";
const std::vector<Opm::VFPInjTable> tables = RimVfpTableExtractor::extractVfpInjectionTables( filename );
if ( wells.find( strippedWellName ) != wells.end() )
{
QString gridFileName = m_case->gridFileName();
QFileInfo fi( gridFileName );
// TODO: populate with real data
populatePlotWidgetWithCurveData( m_plotWidget, tables );
std::string filename = fi.canonicalPath().toStdString() + "/INCLUDE/VFP/" + strippedWellName + ".Ecl";
const std::vector<Opm::VFPInjTable> tables = RimVfpTableExtractor::extractVfpInjectionTables( filename );
populatePlotWidgetWithCurveData( m_plotWidget, tables );
}
}
else
{
std::set<std::string> wells = {"B1BH", "B2H", "B3H", "D1CH", "B4DH", "E1H", "D2H", "D3BH", "E3CH"};
std::string strippedWellName = QString( m_wellName() ).remove( "-" ).toStdString();
// TODO: Maybe display the phase?
// if ( m_phase == RiaDefines::OIL_PHASE )
// phaseString = "Oil";
// else if ( m_phase == RiaDefines::GAS_PHASE )
// phaseString = "Gas";
// else if ( m_phase == RiaDefines::WATER_PHASE )
// phaseString = "Water";
if ( wells.find( strippedWellName ) != wells.end() )
{
QString gridFileName = m_case->gridFileName();
QFileInfo fi( gridFileName );
std::string filename = fi.canonicalPath().toStdString() + "/INCLUDE/VFP/" + strippedWellName + ".Ecl";
const std::vector<Opm::VFPProdTable> tables = RimVfpTableExtractor::extractVfpProductionTables( filename );
populatePlotWidgetWithCurveData( m_plotWidget, tables, m_productionTableType() );
}
}
}
const QString plotTitleStr = QString( "%1 Vertical Flow Performance Plot" ).arg( m_wellName );
m_plotWidget->setTitle( plotTitleStr );
m_plotWidget->setAxisTitleText( QwtPlot::xBottom, "Liquid Flow Rate [sm3/d]" );
m_plotWidget->setAxisTitleText( QwtPlot::yLeft, "Bottom Hole Pressure [Bar]" );
if ( isInjector )
{
m_plotWidget->setAxisTitleText( QwtPlot::xBottom, "Liquid Flow Rate [sm3/d]" );
m_plotWidget->setAxisTitleText( QwtPlot::yLeft, "Bottom Hole Pressure [Bar]" );
}
else
{
m_plotWidget->setAxisTitleText( QwtPlot::xBottom, "x axis (todo) [x axis unit]" );
m_plotWidget->setAxisTitleText( QwtPlot::yLeft, "y axis [y axis unit]" );
}
m_plotWidget->setAxisTitleEnabled( QwtPlot::xBottom, true );
m_plotWidget->setAxisTitleEnabled( QwtPlot::yLeft, true );
@ -424,7 +470,101 @@ void RimVfpPlot::populatePlotWidgetWithCurveData( RiuQwtPlotWidget* plotWidget,
QwtPlotCurve* curve = new QwtPlotCurve;
// Convert from Pascal to Bar
curve->setTitle( QString( "THP: %1 Bar" ).arg( table.getTHPAxis()[thp] / 100000.0 ) );
// curve->setBrush( qtClr );
QwtSymbol* symbol = new QwtSymbol( QwtSymbol::Ellipse, QBrush( qtClr ), QPen( Qt::red, 2 ), QSize( 8, 8 ) );
curve->setSymbol( symbol );
curve->setSamples( xVals.data(), yVals.data(), numValues );
curve->attach( plotWidget );
curve->show();
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::populatePlotWidgetWithCurveData( RiuQwtPlotWidget* plotWidget,
const std::vector<Opm::VFPProdTable>& tables,
RimVfpPlot::ProductionTableType productionTableType )
{
cvf::Trace::show( "RimVfpPlot::populatePlotWidgetWithCurves()" );
plotWidget->detachItems( QwtPlotItem::Rtti_PlotCurve );
plotWidget->setAxisScale( QwtPlot::xBottom, 0, 1 );
plotWidget->setAxisScale( QwtPlot::yLeft, 0, 1 );
plotWidget->setAxisAutoScale( QwtPlot::xBottom, true );
plotWidget->setAxisAutoScale( QwtPlot::yLeft, true );
size_t numTables = tables.size();
for ( size_t i = 0; i < numTables; i++ )
{
const Opm::VFPProdTable table = tables[i];
std::cout << "Datum depth: " << table.getDatumDepth() << std::endl;
std::cout << "Table number: " << table.getTableNum() << std::endl;
std::cout << "Flow type: " << static_cast<int>( table.getFloType() ) << std::endl;
std::cout << "Flo axis: " << table.getFloAxis().size() << std::endl;
std::cout << "THP axis: " << table.getTHPAxis().size() << std::endl;
std::cout << "WFR axis: " << table.getWFRAxis().size() << std::endl;
std::cout << "GFR axis: " << table.getGFRAxis().size() << std::endl;
std::cout << "ALQ axis: " << table.getALQAxis().size() << std::endl;
std::cout << "THP Axis:\n";
for ( size_t x = 0; x < table.getTHPAxis().size(); x++ )
{
std::cout << " " << table.getTHPAxis()[x];
}
std::cout << "\n";
for ( size_t thp_idx = 0; thp_idx < table.getTHPAxis().size(); thp_idx++ )
{
size_t wfr_idx = table.getWFRAxis().size() - 1;
size_t gfr_idx = table.getGFRAxis().size() - 1;
size_t alq_idx = table.getALQAxis().size() - 1;
size_t flo_idx = table.getFloAxis().size() - 1;
std::vector<double> xVals;
if ( productionTableType == RimVfpPlot::ProductionTableType::WATER_CUT )
{
xVals = table.getWFRAxis();
}
else if ( productionTableType == RimVfpPlot::ProductionTableType::GAS_LIQUID_RATIO )
{
xVals = table.getGFRAxis();
}
else if ( productionTableType == RimVfpPlot::ProductionTableType::ARTIFICIAL_LIFT_QUANTITY )
{
xVals = table.getALQAxis();
}
else if ( productionTableType == RimVfpPlot::ProductionTableType::LIQUID_FLOW_RATE )
{
xVals = table.getFloAxis();
}
size_t numValues = xVals.size();
std::vector<double> yVals( numValues, 0.0 );
for ( size_t y = 0; y < numValues; y++ )
{
if ( productionTableType == RimVfpPlot::ProductionTableType::WATER_CUT )
wfr_idx = y;
else if ( productionTableType == RimVfpPlot::ProductionTableType::GAS_LIQUID_RATIO )
gfr_idx = y;
else if ( productionTableType == RimVfpPlot::ProductionTableType::ARTIFICIAL_LIFT_QUANTITY )
alq_idx = y;
else if ( productionTableType == RimVfpPlot::ProductionTableType::LIQUID_FLOW_RATE )
flo_idx = y;
// Convert from Pascal to Bar
yVals[y] = table( thp_idx, wfr_idx, gfr_idx, alq_idx, flo_idx ) / 100000.0;
}
cvf::Color3f cvfClr = cvf::Color3::BLUE;
QColor qtClr = RiaColorTools::toQColor( cvfClr );
QwtPlotCurve* curve = new QwtPlotCurve;
// Convert from Pascal to Bar
curve->setTitle( QString( "THP: %1 Bar" ).arg( table.getTHPAxis()[thp_idx] / 100000.0 ) );
QwtSymbol* symbol = new QwtSymbol( QwtSymbol::Ellipse, QBrush( qtClr ), QPen( Qt::red, 2 ), QSize( 8, 8 ) );
curve->setSymbol( symbol );
@ -442,8 +582,12 @@ void RimVfpPlot::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiO
{
uiOrdering.add( &m_case );
uiOrdering.add( &m_wellName );
uiOrdering.add( &m_tableType );
uiOrdering.add( &m_productionTableType );
m_productionTableType.uiCapability()->setUiHidden( m_tableType != RimVfpPlot::TableType::PRODUCTION );
RimPlot::defineUiOrdering( uiConfigName, uiOrdering );
uiOrdering.skipRemainingFields( true );
// RimPlot::defineUiOrdering( uiConfigName, uiOrdering );
}
//--------------------------------------------------------------------------------------------------

View File

@ -25,6 +25,7 @@
#include <QPointer>
#include "opm/parser/eclipse/EclipseState/Schedule/VFPInjTable.hpp"
#include "opm/parser/eclipse/EclipseState/Schedule/VFPProdTable.hpp"
class RimEclipseResultCase;
class RimFlowDiagSolution;
@ -39,6 +40,20 @@ class RimVfpPlot : public RimPlot
CAF_PDM_HEADER_INIT;
public:
enum class TableType
{
INJECTION,
PRODUCTION
};
enum class ProductionTableType
{
LIQUID_FLOW_RATE,
ARTIFICIAL_LIFT_QUANTITY,
WATER_CUT,
GAS_LIQUID_RATIO
};
RimVfpPlot();
~RimVfpPlot() override;
@ -82,6 +97,9 @@ private:
void fixupDependentFieldsAfterCaseChange();
static void populatePlotWidgetWithCurveData( RiuQwtPlotWidget* plotWidget, const std::vector<Opm::VFPInjTable>& tables );
static void populatePlotWidgetWithCurveData( RiuQwtPlotWidget* plotWidget,
const std::vector<Opm::VFPProdTable>& tables,
RimVfpPlot::ProductionTableType productionTableType );
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
@ -93,5 +111,8 @@ private:
caf::PdmPtrField<RimEclipseResultCase*> m_case;
caf::PdmField<QString> m_wellName;
caf::PdmField<caf::AppEnum<RimVfpPlot::TableType>> m_tableType;
caf::PdmField<caf::AppEnum<RimVfpPlot::ProductionTableType>> m_productionTableType;
QPointer<RiuQwtPlotWidget> m_plotWidget;
};

View File

@ -65,3 +65,29 @@ std::vector<Opm::VFPInjTable> RimVfpTableExtractor::extractVfpInjectionTables( c
return tables;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<Opm::VFPProdTable> RimVfpTableExtractor::extractVfpProductionTables( const std::string& filename )
{
std::vector<Opm::VFPProdTable> tables;
Opm::Parser parser;
auto deck = parser.parseFile( filename );
std::string myKeyword = "VFPPROD";
auto keywordList = deck.getKeywordList( myKeyword );
Opm::UnitSystem unitSystem;
for ( auto kw : keywordList )
{
auto name = kw->name();
Opm::VFPProdTable table( *kw, unitSystem );
tables.push_back( table );
}
return tables;
}

View File

@ -22,6 +22,7 @@
#include <vector>
#include "opm/parser/eclipse/EclipseState/Schedule/VFPInjTable.hpp"
#include "opm/parser/eclipse/EclipseState/Schedule/VFPProdTable.hpp"
//--------------------------------------------------------------------------------------------------
///
@ -29,5 +30,6 @@
class RimVfpTableExtractor
{
public:
static std::vector<Opm::VFPInjTable> extractVfpInjectionTables( const std::string& filename );
static std::vector<Opm::VFPInjTable> extractVfpInjectionTables( const std::string& filename );
static std::vector<Opm::VFPProdTable> extractVfpProductionTables( const std::string& filename );
};