Add RimVfpTableData used to represent connection to file and data

Extract data management from RimVfpPlot. Use pointer from RimVfpPlot to RimVfpTableData.
This commit is contained in:
Magne Sjaastad 2024-05-13 08:54:40 +02:00
parent b8391e6f92
commit ff9b13163a
28 changed files with 1591 additions and 717 deletions

View File

@ -95,6 +95,7 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RicImportSummaryCalculationExpressionsFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicImportWellLogCsvFileFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicNewViewForGridEnsembleFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicNewVfpPlotFeature.h
)
set(SOURCE_GROUP_SOURCE_FILES
@ -193,6 +194,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RicImportSummaryCalculationExpressionsFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicImportWellLogCsvFileFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewViewForGridEnsembleFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewVfpPlotFeature.cpp
)
if(RESINSIGHT_USE_QT_CHARTS)

View File

@ -27,6 +27,7 @@
#include "RimWellPathFractureCollection.h"
#include "cafPdmUiItem.h"
#include "cafPdmUiObjectHandle.h"
#include "cafSelectionManager.h"
#include <QAction>
@ -115,6 +116,14 @@ bool RicDeleteSubItemsFeature::hasDeletableSubItems( caf::PdmUiItem* uiItem )
}
}
{
auto collection = dynamic_cast<RimPlotCollection*>( uiItem );
if ( collection && collection->plotCount() > 0 )
{
return true;
}
}
return false;
}
@ -227,5 +236,18 @@ void RicDeleteSubItemsFeature::deleteSubItems( bool onlyDeleteUnchecked )
if ( proj ) proj->reloadCompletionTypeResultsInAllViews();
}
}
{
auto collection = dynamic_cast<RimPlotCollection*>( item );
if ( collection )
{
collection->deleteAllPlots();
if ( auto objHandle = dynamic_cast<caf::PdmUiObjectHandle*>( item ) )
{
objHandle->updateConnectedEditors();
}
}
}
}
}

View File

@ -23,6 +23,7 @@
#include "RimMainPlotCollection.h"
#include "VerticalFlowPerformance/RimVfpDataCollection.h"
#include "VerticalFlowPerformance/RimVfpDeck.h"
#include "VerticalFlowPerformance/RimVfpPlot.h"
#include "VerticalFlowPerformance/RimVfpPlotCollection.h"
@ -38,15 +39,6 @@
CAF_CMD_SOURCE_INIT( RicImportVfpDataFeature, "RicImportVfpDataFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicImportVfpDataFeature::isCommandEnabled() const
{
auto plotColl = caf::firstAncestorOfTypeFromSelectedObject<RimVfpPlotCollection>();
return ( plotColl != nullptr );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -83,47 +75,17 @@ void RicImportVfpDataFeature::onActionTriggered( bool isChecked )
std::vector<RimVfpPlot*> vfpPlots;
std::vector<RimVfpDeck*> vfpDecks;
auto vfpDataColl = RimVfpDataCollection::instance();
for ( const auto& fileName : fileNames )
{
if ( fileName.contains( ".DATA" ) )
{
auto vfpDeck = vfpPlotColl->addDeck( fileName );
vfpDecks.push_back( vfpDeck );
}
else
{
auto vfpPlot = new RimVfpPlot();
vfpPlot->setFileName( fileName );
vfpPlotColl->addPlot( vfpPlot );
vfpPlots.push_back( vfpPlot );
}
auto vfpDataSource = vfpDataColl->appendTableDataObject( fileName );
auto firstPlot = vfpPlotColl->createAndAppendPlots( vfpDataSource );
vfpDataColl->updateAllRequiredEditors();
RiuPlotMainWindowTools::onObjectAppended( firstPlot, firstPlot );
}
vfpPlotColl->updateConnectedEditors();
for ( auto deck : vfpDecks )
{
deck->loadDataAndUpdate();
deck->updateConnectedEditors();
}
for ( auto plot : vfpPlots )
{
plot->loadDataAndUpdate();
}
RiuPlotMainWindowTools::showPlotMainWindow();
if ( !vfpPlots.empty() )
{
RiuPlotMainWindowTools::onObjectAppended( vfpPlots.front() );
}
if ( !vfpDecks.empty() )
{
RiuPlotMainWindowTools::onObjectAppended( vfpDecks.front() );
}
vfpPlotColl->updateAllRequiredEditors();
}
//--------------------------------------------------------------------------------------------------

View File

@ -28,7 +28,6 @@ class RicImportVfpDataFeature : public caf::CmdFeature
CAF_CMD_HEADER_INIT;
private:
bool isCommandEnabled() const override;
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;
};

View File

@ -0,0 +1,59 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 "RicNewVfpPlotFeature.h"
#include "RimMainPlotCollection.h"
#include "VerticalFlowPerformance/RimVfpDataCollection.h"
#include "VerticalFlowPerformance/RimVfpPlotCollection.h"
#include "VerticalFlowPerformance/RimVfpTableData.h"
#include "cafSelectionManagerTools.h"
#include "RiuPlotMainWindowTools.h"
#include <QAction>
CAF_CMD_SOURCE_INIT( RicNewVfpPlotFeature, "RicNewVfpPlotFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicNewVfpPlotFeature::onActionTriggered( bool isChecked )
{
RimVfpPlotCollection* vfpPlotColl = RimMainPlotCollection::current()->vfpPlotCollection();
if ( !vfpPlotColl ) return;
auto selectedTableData = caf::selectedObjectsByTypeStrict<RimVfpTableData*>();
for ( auto tableData : selectedTableData )
{
RimVfpPlot* firstPlot = vfpPlotColl->createAndAppendPlots( tableData );
vfpPlotColl->updateConnectedEditors();
RiuPlotMainWindowTools::onObjectAppended( firstPlot, firstPlot );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicNewVfpPlotFeature::setupActionLook( QAction* actionToSetup )
{
actionToSetup->setText( "Create VFP Plot" );
actionToSetup->setIcon( QIcon( ":/VfpPlot.svg" ) );
}

View File

@ -0,0 +1,33 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafCmdFeature.h"
//==================================================================================================
///
//==================================================================================================
class RicNewVfpPlotFeature : public caf::CmdFeature
{
CAF_CMD_HEADER_INIT;
private:
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;
};

View File

@ -44,10 +44,7 @@ bool RicDeleteSubPlotFeature::isCommandEnabled() const
{
if ( RicWellLogPlotCurveFeatureImpl::parentWellAllocationPlot() ) return false;
std::vector<RimPlot*> selection;
getSelection( selection );
return ( !selection.empty() );
return isAnyDeletablePlotSelected();
}
//--------------------------------------------------------------------------------------------------
@ -150,3 +147,23 @@ void RicDeleteSubPlotFeature::getSelection( std::vector<RimPlot*>& selection ) c
caf::SelectionManager::instance()->objectsByType( &selection );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicDeleteSubPlotFeature::isAnyDeletablePlotSelected() const
{
std::vector<RimPlot*> selection;
getSelection( selection );
for ( RimPlot* plot : selection )
{
if ( !plot ) continue;
RimMultiPlot* multiPlot = plot->firstAncestorOrThisOfType<RimMultiPlot>();
RimWellLogPlot* wellLogPlot = plot->firstAncestorOrThisOfType<RimWellLogPlot>();
if ( multiPlot || wellLogPlot ) return true;
}
return false;
}

View File

@ -39,4 +39,5 @@ protected:
private:
void getSelection( std::vector<RimPlot*>& selection ) const;
bool isAnyDeletablePlotSelected() const;
};

View File

@ -85,94 +85,6 @@ Opm::VFPProdTable createProductionTable( const Opm::DeckKeyword& keyword )
return { keyword, gaslift_opt_active, unitSystem };
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<Opm::VFPInjTable> extractVfpInjectionTables( const std::string& filename )
{
std::vector<Opm::VFPInjTable> tables;
try
{
Opm::Parser parser( false );
const ::Opm::ParserKeywords::VFPINJ kw1;
const ::Opm::ParserKeywords::VFPIDIMS kw2;
parser.addParserKeyword( kw1 );
parser.addParserKeyword( kw2 );
auto deck = parser.parseFile( filename );
std::string keyword = ::Opm::ParserKeywords::VFPINJ::keywordName;
auto keywordList = deck.getKeywordList( keyword );
for ( auto kw : keywordList )
{
auto table = createInjectionTable( *kw );
tables.push_back( table );
}
}
catch ( Opm::OpmInputError& e )
{
QString text = QString( "Error detected when parsing '%1'. Imported data might be missing or incomplete.\n%2" )
.arg( QString::fromStdString( filename ) )
.arg( QString::fromStdString( e.what() ) );
RiaLogging::warning( text );
}
catch ( ... )
{
QString text =
QString( "Error detected when parsing '%1'. Imported data might be missing or incomplete." ).arg( QString::fromStdString( filename ) );
RiaLogging::warning( text );
}
return tables;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<Opm::VFPProdTable> extractVfpProductionTables( const std::string& filename )
{
std::vector<Opm::VFPProdTable> tables;
try
{
Opm::Parser parser( false );
const ::Opm::ParserKeywords::VFPPROD kw1;
parser.addParserKeyword( kw1 );
auto deck = parser.parseFile( filename );
std::string keyword = ::Opm::ParserKeywords::VFPPROD::keywordName;
auto keywordList = deck.getKeywordList( keyword );
for ( auto kw : keywordList )
{
auto table = createProductionTable( *kw );
tables.push_back( table );
}
}
catch ( Opm::OpmInputError& e )
{
QString text = QString( "Error detected when parsing '%1'. Imported data might be missing or incomplete.\n%2" )
.arg( QString::fromStdString( filename ) )
.arg( QString::fromStdString( e.what() ) );
RiaLogging::warning( text );
}
catch ( ... )
{
QString text =
QString( "Error detected when parsing '%1'. Imported data might be missing or incomplete." ).arg( QString::fromStdString( filename ) );
RiaLogging::warning( text );
}
return tables;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -30,8 +30,6 @@
//--------------------------------------------------------------------------------------------------
namespace RiaOpmParserTools
{
std::vector<Opm::VFPInjTable> extractVfpInjectionTables( const std::string& filename );
std::vector<Opm::VFPProdTable> extractVfpProductionTables( const std::string& filename );
std::pair<std::vector<Opm::VFPProdTable>, std::vector<Opm::VFPInjTable>> extractVfpTablesFromDataFile( const std::string& dataDeckFilename );

View File

@ -38,6 +38,7 @@
#include "RimWellPathCollection.h"
#include "Polygons/RimPolygonCollection.h"
#include "VerticalFlowPerformance/RimVfpDataCollection.h"
CAF_PDM_SOURCE_INIT( RimOilField, "ResInsightOilField" );
//--------------------------------------------------------------------------------------------------
@ -93,6 +94,9 @@ RimOilField::RimOilField()
ensembleWellLogsCollection = new RimEnsembleWellLogsCollection();
polygonCollection = new RimPolygonCollection();
CAF_PDM_InitFieldNoDefault( &vfpDataCollection, "VfpDataCollection", "VFP Data" );
vfpDataCollection = new RimVfpDataCollection();
m_fractureTemplateCollection_OBSOLETE = new RimFractureTemplateCollection;
m_fractureTemplateCollection_OBSOLETE.xmlCapability()->setIOWritable( false );
}

View File

@ -44,6 +44,7 @@ class RimEnsembleWellLogsCollection;
class RimPolygonCollection;
class RimEclipseViewCollection;
class RimEclipseContourMapViewCollection;
class RimVfpDataCollection;
//==================================================================================================
///
@ -79,6 +80,7 @@ public:
caf::PdmChildField<RimEnsembleWellLogsCollection*> ensembleWellLogsCollection;
caf::PdmChildField<RimPolygonCollection*> polygonCollection;
caf::PdmChildField<RimEclipseContourMapViewCollection*> eclipseContourMapCollection;
caf::PdmChildField<RimVfpDataCollection*> vfpDataCollection;
protected:
void initAfterRead() override;

View File

@ -99,6 +99,8 @@
#include "RimWellLogPlotCollection.h"
#include "RimWellPath.h"
#include "RimWellPathCollection.h"
#include "VerticalFlowPerformance/RimVfpDataCollection.h"
#include "VerticalFlowPerformance/RimVfpPlotCollection.h"
#include "Tools/RiaVariableMapper.h"
@ -1458,6 +1460,10 @@ void RimProject::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, Q
{
uiTreeOrdering.add( oilField->ensembleWellLogsCollection() );
}
if ( oilField->vfpDataCollection() )
{
uiTreeOrdering.add( oilField->vfpDataCollection() );
}
}
}
else if ( uiConfigName == "PlotWindow.Scripts" || uiConfigName == "MainWindow.Scripts" )

View File

@ -1396,17 +1396,10 @@ void RimSummaryCurve::updateTimeAnnotations()
void RimSummaryCurve::updateLegendEntryVisibilityNoPlotUpdate()
{
if ( !m_plotCurve ) return;
auto ensembleCurveSet = firstAncestorOrThisOfType<RimEnsembleCurveSet>();
if ( ensembleCurveSet )
{
return;
}
if ( !firstAncestorOrThisOfType<RimEnsembleCurveSet>() ) return;
bool showLegendInPlot = m_showLegend();
auto summaryPlot = firstAncestorOrThisOfType<RimSummaryPlot>();
if ( summaryPlot )
if ( auto summaryPlot = firstAncestorOrThisOfType<RimSummaryPlot>() )
{
bool anyCalculated = false;
for ( const auto c : summaryPlot->summaryCurves() )

View File

@ -3,6 +3,8 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RimVfpDeck.h
${CMAKE_CURRENT_LIST_DIR}/RimVfpPlot.h
${CMAKE_CURRENT_LIST_DIR}/RimVfpPlotCollection.h
${CMAKE_CURRENT_LIST_DIR}/RimVfpTableData.h
${CMAKE_CURRENT_LIST_DIR}/RimVfpDataCollection.h
)
set(SOURCE_GROUP_SOURCE_FILES
@ -10,6 +12,8 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RimVfpDefines.cpp
${CMAKE_CURRENT_LIST_DIR}/RimVfpPlot.cpp
${CMAKE_CURRENT_LIST_DIR}/RimVfpPlotCollection.cpp
${CMAKE_CURRENT_LIST_DIR}/RimVfpTableData.cpp
${CMAKE_CURRENT_LIST_DIR}/RimVfpDataCollection.cpp
)
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})

View File

@ -0,0 +1,73 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 "RimVfpDataCollection.h"
#include "RimOilField.h"
#include "RimProject.h"
#include "RimVfpPlotCollection.h"
#include "RimVfpTableData.h"
CAF_PDM_SOURCE_INIT( RimVfpDataCollection, "RimVfpDataCollection" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpDataCollection::RimVfpDataCollection()
{
CAF_PDM_InitObject( "VFP Data", ":/VfpPlotCollection.svg" );
CAF_PDM_InitFieldNoDefault( &m_vfpTableData, "VfpPlots", "Vertical Flow Performance Data" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpDataCollection* RimVfpDataCollection::instance()
{
return RimProject::current()->activeOilField()->vfpDataCollection();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpTableData* RimVfpDataCollection::appendTableDataObject( const QString& fileName )
{
auto* vfpTableData = new RimVfpTableData();
vfpTableData->setFileName( fileName );
m_vfpTableData.push_back( vfpTableData );
return vfpTableData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimVfpTableData*> RimVfpDataCollection::vfpTableData() const
{
return m_vfpTableData.childrenByType();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpDataCollection::appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const
{
RimVfpPlotCollection::addImportItems( menuBuilder );
}

View File

@ -0,0 +1,46 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafPdmChildArrayField.h"
#include "cafPdmObject.h"
class RimVfpTableData;
//==================================================================================================
///
///
//==================================================================================================
class RimVfpDataCollection : public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
public:
RimVfpDataCollection();
static RimVfpDataCollection* instance();
RimVfpTableData* appendTableDataObject( const QString& fileName );
std::vector<RimVfpTableData*> vfpTableData() const;
private:
void appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const override;
private:
caf::PdmChildArrayField<RimVfpTableData*> m_vfpTableData;
};

View File

@ -18,14 +18,14 @@
#include "RimVfpDeck.h"
#include "RiaOpmParserTools.h"
#include "RigVfpTables.h"
#include "RimVfpDataCollection.h"
#include "RimVfpPlotCollection.h"
#include "RimVfpTableData.h"
#include "cafPdmUiTreeOrdering.h"
#include <QFileInfo>
CAF_PDM_SOURCE_INIT( RimVfpDeck, "RimVfpDeck" );
//--------------------------------------------------------------------------------------------------
@ -35,7 +35,7 @@ RimVfpDeck::RimVfpDeck()
{
CAF_PDM_InitObject( "VFP Plot", ":/VfpPlot.svg" );
CAF_PDM_InitFieldNoDefault( &m_filePath, "FilePath", "File Path" );
CAF_PDM_InitFieldNoDefault( &m_vfpTableData, "VfpTableData", "VFP Data Source" );
CAF_PDM_InitFieldNoDefault( &m_vfpPlotCollection, "VfpPlotCollection", "Plot Collection" );
m_vfpPlotCollection = new RimVfpPlotCollection();
@ -45,9 +45,9 @@ RimVfpDeck::RimVfpDeck()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpDeck::setFileName( const QString& filename )
void RimVfpDeck::setDataSource( RimVfpTableData* tableData )
{
m_filePath = filename;
m_vfpTableData = tableData;
}
//--------------------------------------------------------------------------------------------------
@ -57,50 +57,40 @@ void RimVfpDeck::loadDataAndUpdate()
{
updateObjectName();
auto createRimVfpPlot = [&]() -> RimVfpPlot*
{
auto plot = new RimVfpPlot();
plot->setFileName( m_filePath().path() );
return plot;
};
std::vector<RimVfpPlot*> currentPlots = m_vfpPlotCollection->plots();
auto [vfpProdTables, vfpInjTables] = RiaOpmParserTools::extractVfpTablesFromDataFile( m_filePath().path().toStdString() );
for ( const auto& prodTable : vfpProdTables )
if ( m_vfpTableData )
{
RimVfpPlot* plot = m_vfpPlotCollection->plotForTableNumber( prodTable.getTableNum() );
if ( !plot )
{
plot = createRimVfpPlot();
m_vfpPlotCollection->addPlot( plot );
}
else
{
std::erase( currentPlots, plot );
}
plot->setProductionTable( prodTable );
plot->setDataIsImportedExternally( true );
plot->setDeletable( false );
plot->loadDataAndUpdate();
}
m_vfpTableData->ensureDataIsImported();
for ( const auto& injTable : vfpInjTables )
{
RimVfpPlot* plot = m_vfpPlotCollection->plotForTableNumber( injTable.getTableNum() );
if ( !plot )
if ( m_vfpTableData->vfpTables() )
{
plot = createRimVfpPlot();
m_vfpPlotCollection->addPlot( plot );
auto tables = m_vfpTableData->vfpTables();
auto allTableNumbers = tables->productionTableNumbers();
auto injTableNumbers = tables->injectionTableNumbers();
allTableNumbers.insert( allTableNumbers.end(), injTableNumbers.begin(), injTableNumbers.end() );
for ( const auto& number : allTableNumbers )
{
RimVfpPlot* plot = m_vfpPlotCollection->plotForTableNumber( number );
if ( !plot )
{
plot = new RimVfpPlot();
plot->setDataSource( m_vfpTableData );
plot->setTableNumber( number );
plot->initializeObject();
m_vfpPlotCollection->addPlot( plot );
}
else
{
std::erase( currentPlots, plot );
}
plot->setDeletable( false );
plot->loadDataAndUpdate();
}
}
else
{
std::erase( currentPlots, plot );
}
plot->setInjectionTable( injTable );
plot->setDataIsImportedExternally( true );
plot->setDeletable( false );
plot->loadDataAndUpdate();
}
for ( auto plotToDelete : currentPlots )
@ -109,6 +99,15 @@ void RimVfpDeck::loadDataAndUpdate()
delete plotToDelete;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimVfpPlot*> RimVfpDeck::plots() const
{
return m_vfpPlotCollection->plots();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -127,13 +126,30 @@ void RimVfpDeck::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, Q
//--------------------------------------------------------------------------------------------------
void RimVfpDeck::updateObjectName()
{
QString name = "VFP Plots";
QString name = "VFP Deck";
QFileInfo fileInfo( m_filePath().path() );
auto fileName = fileInfo.fileName();
if ( !fileName.isEmpty() )
if ( m_vfpTableData )
{
name += " - " + fileName;
name = m_vfpTableData->name();
}
setName( name );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QList<caf::PdmOptionItemInfo> RimVfpDeck::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions )
{
QList<caf::PdmOptionItemInfo> options;
if ( fieldNeedingOptions == &m_vfpTableData )
{
RimVfpDataCollection* vfpDataCollection = RimVfpDataCollection::instance();
for ( auto table : vfpDataCollection->vfpTableData() )
{
options.push_back( caf::PdmOptionItemInfo( table->name(), table ) );
}
}
return options;
}

View File

@ -21,8 +21,11 @@
#include "RimNamedObject.h"
#include "cafFilePath.h"
#include "cafPdmPtrField.h"
class RimVfpPlotCollection;
class RimVfpTableData;
class RimVfpPlot;
//--------------------------------------------------------------------------------------------------
/// RimVfpDeck parses a deck file (*.DATA) containing VFP data and creates a collection of VFP plots.
@ -34,14 +37,17 @@ class RimVfpDeck : public RimNamedObject
public:
RimVfpDeck();
void setFileName( const QString& filename );
void setDataSource( RimVfpTableData* tableData );
void loadDataAndUpdate();
private:
void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "" ) override;
void updateObjectName();
std::vector<RimVfpPlot*> plots() const;
private:
caf::PdmField<caf::FilePath> m_filePath;
void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "" ) override;
void updateObjectName();
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
private:
caf::PdmPtrField<RimVfpTableData*> m_vfpTableData;
caf::PdmChildField<RimVfpPlotCollection*> m_vfpPlotCollection;
};

View File

@ -19,22 +19,27 @@
#include "RimVfpPlot.h"
#include "RiaColorTables.h"
#include "RiaColorTools.h"
#include "RiaEclipseUnitTools.h"
#include "RiaOpmParserTools.h"
#include "RigVfpTables.h"
#include "RimPlotAxisProperties.h"
#include "RimPlotCurve.h"
#include "RimProject.h"
#include "RimVfpDataCollection.h"
#include "RimVfpDefines.h"
#include "RimVfpTableData.h"
#include "Tools/RimPlotAxisTools.h"
#include "RiuContextMenuLauncher.h"
#include "RiuPlotCurve.h"
#include "RiuPlotWidget.h"
#include "RiuQwtCurvePointTracker.h"
#include "RiuQwtPlotCurveDefines.h"
#include "RiuQwtPlotWheelZoomer.h"
#include "RiuQwtPlotWidget.h"
#include "RiuQwtCurvePointTracker.h"
#include "RiuQwtPlotWidget.h"
#include "RiuQwtPlotZoomer.h"
#include "cafPdmUiComboBoxEditor.h"
@ -51,39 +56,6 @@
//
//==================================================================================================
class VfpPlotData
{
public:
void setXAxisTitle( const QString& xAxisTitle ) { m_xAxisTitle = xAxisTitle; }
void setYAxisTitle( const QString& yAxisTitle ) { m_yAxisTitle = yAxisTitle; }
const QString& xAxisTitle() const { return m_xAxisTitle; }
const QString& yAxisTitle() const { return m_yAxisTitle; }
void appendCurve( const QString& curveTitle, const std::vector<double>& xData, const std::vector<double>& yData )
{
m_curveTitles.push_back( curveTitle );
m_xData.push_back( xData );
m_yData.push_back( yData );
}
const QString& curveTitle( size_t idx ) const { return m_curveTitles[idx]; }
size_t size() const { return m_xData.size(); }
size_t curveSize( size_t idx ) const { return m_xData[idx].size(); }
const std::vector<double>& xData( size_t idx ) const { return m_xData[idx]; }
const std::vector<double>& yData( size_t idx ) const { return m_yData[idx]; }
private:
QString m_xAxisTitle;
QString m_yAxisTitle;
std::vector<QString> m_curveTitles;
std::vector<std::vector<double>> m_xData;
std::vector<std::vector<double>> m_yData;
};
CAF_PDM_SOURCE_INIT( RimVfpPlot, "VfpPlot" );
//--------------------------------------------------------------------------------------------------
@ -97,7 +69,10 @@ RimVfpPlot::RimVfpPlot()
CAF_PDM_InitField( &m_plotTitle, "PlotTitle", QString( "VFP Plot" ), "Plot Title" );
m_plotTitle.uiCapability()->setUiHidden( true );
CAF_PDM_InitFieldNoDefault( &m_filePath, "FilePath", "File Path" );
CAF_PDM_InitFieldNoDefault( &m_filePath_OBSOLETE, "FilePath", "File Path" );
m_filePath_OBSOLETE.xmlCapability()->setIOWritable( false );
CAF_PDM_InitFieldNoDefault( &m_vfpTableData, "VfpTableData", "VFP Data Source" );
caf::AppEnum<RimVfpDefines::TableType> defaultTableType = RimVfpDefines::TableType::INJECTION;
CAF_PDM_InitField( &m_tableType, "TableType", defaultTableType, "Table Type" );
@ -156,6 +131,8 @@ RimVfpPlot::RimVfpPlot()
connectAxisSignals( m_xAxisProperties() );
connectAxisSignals( m_yAxisProperties() );
CAF_PDM_InitFieldNoDefault( &m_plotCurves, "PlotCurves", "Curves" );
m_showWindow = true;
m_showPlotLegends = true;
m_dataIsImportedExternally = false;
@ -163,6 +140,8 @@ RimVfpPlot::RimVfpPlot()
setAsPlotMdiWindow();
setDeletable( true );
m_vfpTables = std::make_unique<RigVfpTables>();
}
//--------------------------------------------------------------------------------------------------
@ -177,9 +156,43 @@ RimVfpPlot::~RimVfpPlot()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::setFileName( const QString& filename )
void RimVfpPlot::setDataSource( RimVfpTableData* vfpTableData )
{
m_filePath = filename;
m_vfpTableData = vfpTableData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::setTableNumber( int tableNumber )
{
m_tableNumber = tableNumber;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::initializeObject()
{
if ( !vfpTables() ) return;
auto tableNumber = m_tableNumber();
// Always use the available table number if only one table is available
auto prodTableNumbers = vfpTables()->productionTableNumbers();
auto injTableNumbers = vfpTables()->injectionTableNumbers();
if ( prodTableNumbers.size() == 1 && injTableNumbers.empty() )
{
tableNumber = prodTableNumbers.front();
}
else if ( injTableNumbers.size() == 1 && prodTableNumbers.empty() )
{
tableNumber = injTableNumbers.front();
}
auto table = vfpTables()->getTableInitialData( tableNumber );
initializeFromInitData( table );
}
//--------------------------------------------------------------------------------------------------
@ -260,72 +273,35 @@ void RimVfpPlot::updateLegend()
//--------------------------------------------------------------------------------------------------
QString RimVfpPlot::asciiDataForPlotExport() const
{
QString filePath = m_filePath.v().path();
if ( !filePath.isEmpty() )
if ( !vfpTables() ) return {};
auto tableText = vfpTables()->asciiDataForTable( m_tableNumber(),
m_primaryVariable(),
m_familyVariable(),
m_interpolatedVariable(),
m_flowingPhase(),
tableSelection() );
QString wellName;
if ( m_vfpTableData )
{
QFileInfo fi( filePath );
QString wellName = fi.baseName();
VfpPlotData plotData;
if ( m_tableType() == RimVfpDefines::TableType::PRODUCTION )
wellName = m_vfpTableData->name();
}
else
{
QString filePath = m_filePath_OBSOLETE.v().path();
if ( !filePath.isEmpty() )
{
if ( m_prodTable )
{
populatePlotData( *m_prodTable, m_primaryVariable(), m_familyVariable(), m_interpolatedVariable(), m_flowingPhase(), plotData );
}
QFileInfo fi( filePath );
QString wellName = fi.baseName();
}
else
{
if ( m_injectionTable )
{
populatePlotData( *m_injectionTable, m_interpolatedVariable(), m_flowingPhase(), plotData );
}
}
QString plotTitle =
generatePlotTitle( wellName, m_tableNumber(), m_tableType(), m_interpolatedVariable(), m_primaryVariable(), m_familyVariable() );
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 QString( "%1\n\n%2" ).arg( plotTitle ).arg( dataText );
}
return {};
QString plotTitle =
generatePlotTitle( wellName, m_tableNumber(), m_tableType(), m_interpolatedVariable(), m_primaryVariable(), m_familyVariable() );
return QString( "%1\n\n%2" ).arg( plotTitle ).arg( tableText );
}
//--------------------------------------------------------------------------------------------------
@ -333,6 +309,13 @@ QString RimVfpPlot::asciiDataForPlotExport() const
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::reattachAllCurves()
{
for ( auto curve : m_plotCurves() )
{
if ( curve->isChecked() )
{
curve->setParentPlotNoReplot( m_plotWidget );
}
}
}
//--------------------------------------------------------------------------------------------------
@ -340,6 +323,10 @@ void RimVfpPlot::reattachAllCurves()
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::detachAllCurves()
{
for ( auto curve : m_plotCurves() )
{
curve->detach();
}
}
//--------------------------------------------------------------------------------------------------
@ -385,24 +372,6 @@ void RimVfpPlot::zoomAll()
updatePlotWidgetFromAxisRanges();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::setProductionTable( const Opm::VFPProdTable& table )
{
m_prodTable = std::make_unique<Opm::VFPProdTable>( table );
m_injectionTable.reset();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::setInjectionTable( const Opm::VFPInjTable& table )
{
m_prodTable.reset();
m_injectionTable = std::make_unique<Opm::VFPInjTable>( table );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -422,8 +391,12 @@ int RimVfpPlot::tableNumber() const
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::doRemoveFromCollection()
void RimVfpPlot::onChildrenUpdated( caf::PdmChildArrayFieldHandle* childArray, std::vector<caf::PdmObjectHandle*>& updatedObjects )
{
detachAllCurves();
reattachAllCurves();
m_plotWidget->scheduleReplot();
}
//--------------------------------------------------------------------------------------------------
@ -500,57 +473,22 @@ void RimVfpPlot::onLoadDataAndUpdate()
return;
}
m_plotWidget->detachItems( RiuPlotWidget::PlotItemType::CURVE );
updateLegend();
QString wellName;
if ( !m_dataIsImportedExternally )
if ( vfpTables() )
{
QString filePath = m_filePath.v().path();
if ( !filePath.isEmpty() )
{
QFileInfo fi( filePath );
wellName = fi.baseName();
wellName = m_vfpTableData->baseFileName();
// Try to read the file as an prod table first (most common)
const std::vector<Opm::VFPProdTable> tables = RiaOpmParserTools::extractVfpProductionTables( filePath.toStdString() );
if ( !tables.empty() )
{
setProductionTable( tables[0] );
}
else
{
const std::vector<Opm::VFPInjTable> tables = RiaOpmParserTools::extractVfpInjectionTables( filePath.toStdString() );
if ( !tables.empty() )
{
setInjectionTable( tables[0] );
}
}
}
}
auto vfpPlotData = vfpTables()->populatePlotData( m_tableNumber(),
m_primaryVariable(),
m_familyVariable(),
m_interpolatedVariable(),
m_flowingPhase(),
tableSelection() );
if ( m_prodTable )
{
auto table = *m_prodTable;
m_tableType = RimVfpDefines::TableType::PRODUCTION;
m_tableNumber = table.getTableNum();
m_referenceDepth = table.getDatumDepth();
m_flowingPhase = getFlowingPhaseType( table );
m_flowingGasFraction = getFlowingGasFractionType( table );
m_flowingWaterFraction = getFlowingWaterFractionType( table );
populatePlotWidgetWithCurveData( m_plotWidget, table, m_primaryVariable(), m_familyVariable() );
}
else if ( m_injectionTable )
{
auto table = *m_injectionTable;
m_tableType = RimVfpDefines::TableType::INJECTION;
m_tableNumber = table.getTableNum();
m_referenceDepth = table.getDatumDepth();
m_flowingPhase = getFlowingPhaseType( table );
populatePlotWidgetWithCurveData( m_plotWidget, table );
populatePlotWidgetWithPlotData( m_plotWidget, vfpPlotData );
}
updatePlotTitle(
@ -559,85 +497,18 @@ void RimVfpPlot::onLoadDataAndUpdate()
m_plotWidget->setAxisTitleEnabled( RiuPlotAxis::defaultBottom(), true );
m_plotWidget->setAxisTitleEnabled( RiuPlotAxis::defaultLeft(), true );
reattachAllCurves();
updatePlotWidgetFromAxisRanges();
m_plotWidget->scheduleReplot();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::populatePlotWidgetWithCurveData( RiuPlotWidget* plotWidget, const Opm::VFPInjTable& table )
{
VfpPlotData plotData;
populatePlotData( table, m_interpolatedVariable(), m_flowingPhase(), plotData );
populatePlotWidgetWithPlotData( plotWidget, plotData );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::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 );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::populatePlotWidgetWithCurveData( RiuPlotWidget* plotWidget,
const Opm::VFPProdTable& table,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable )
{
VfpPlotData plotData;
populatePlotData( table, primaryVariable, familyVariable, m_interpolatedVariable(), m_flowingPhase(), plotData );
populatePlotWidgetWithPlotData( plotWidget, plotData );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::populatePlotWidgetWithPlotData( RiuPlotWidget* plotWidget, const VfpPlotData& plotData )
{
plotWidget->detachItems( RiuPlotWidget::PlotItemType::CURVE );
plotWidget->setAxisScale( RiuPlotAxis::defaultBottom(), 0, 1 );
plotWidget->setAxisScale( RiuPlotAxis::defaultLeft(), 0, 1 );
plotWidget->setAxisAutoScale( RiuPlotAxis::defaultBottom(), true );
@ -645,25 +516,45 @@ void RimVfpPlot::populatePlotWidgetWithPlotData( RiuPlotWidget* plotWidget, cons
plotWidget->setAxisTitleText( RiuPlotAxis::defaultBottom(), plotData.xAxisTitle() );
plotWidget->setAxisTitleText( RiuPlotAxis::defaultLeft(), plotData.yAxisTitle() );
if ( m_plotCurves.size() != plotData.size() )
{
detachAllCurves();
m_plotCurves.deleteChildren();
for ( auto idx = 0u; idx < plotData.size(); idx++ )
{
QColor qtClr = RiaColorTables::summaryCurveDefaultPaletteColors().cycledQColor( idx );
auto curve = new RimPlotCurve();
curve->setLineStyle( RiuQwtPlotCurveDefines::LineStyleEnum::STYLE_SOLID );
curve->setLineThickness( 2 );
curve->setColor( RiaColorTools::fromQColorTo3f( qtClr ) );
curve->setSymbol( RiuPlotCurveSymbol::SYMBOL_ELLIPSE );
curve->setSymbolSize( 6 );
m_plotCurves.push_back( curve );
}
updateConnectedEditors();
}
auto plotCurves = m_plotCurves.childrenByType();
for ( auto idx = 0u; idx < plotData.size(); idx++ )
{
QColor qtClr = RiaColorTables::summaryCurveDefaultPaletteColors().cycledQColor( idx );
RiuPlotCurve* curve = m_plotWidget->createPlotCurve( nullptr, plotData.curveTitle( idx ) );
auto curve = plotCurves[idx];
if ( !curve ) continue;
curve->setAppearance( RiuQwtPlotCurveDefines::LineStyleEnum::STYLE_SOLID,
RiuQwtPlotCurveDefines::CurveInterpolationEnum::INTERPOLATION_POINT_TO_POINT,
2,
qtClr );
RiuPlotCurveSymbol* symbol = curve->createSymbol( RiuPlotCurveSymbol::PointSymbolEnum::SYMBOL_ELLIPSE );
symbol->setColor( qtClr );
symbol->setSize( 6, 6 );
curve->setSymbol( symbol );
bool useLogarithmicScale = false;
curve->setSamplesFromXValuesAndYValues( plotData.xData( idx ), plotData.yData( idx ), useLogarithmicScale );
curve->attachToPlot( plotWidget );
curve->showInPlot();
curve->setCustomName( plotData.curveTitle( idx ) );
curve->setParentPlotNoReplot( plotWidget );
if ( curve->plotCurve() )
{
bool useLogarithmicScale = false;
curve->plotCurve()->setSamplesFromXValuesAndYValues( plotData.xData( idx ), plotData.yData( idx ), useLogarithmicScale );
}
curve->updateCurveAppearance();
curve->appearanceChanged.connect( this, &RimVfpPlot::curveAppearanceChanged );
}
}
@ -754,66 +645,41 @@ void RimVfpPlot::onPlotZoomed()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::populatePlotData( const Opm::VFPProdTable& table,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase,
VfpPlotData& plotData ) const
void RimVfpPlot::curveAppearanceChanged( const caf::SignalEmitter* emitter )
{
QString xAxisTitle = axisTitle( primaryVariable, flowingPhase );
plotData.setXAxisTitle( xAxisTitle );
scheduleReplot();
}
QString yAxisTitle = QString( "%1 %2" ).arg( caf::AppEnum<RimVfpDefines::InterpolatedVariableType>::uiText( interpolatedVariable ),
getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType::THP ) );
plotData.setYAxisTitle( yAxisTitle );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::initializeFromInitData( const VfpTableInitialData& table )
{
m_tableType = table.isProductionTable ? RimVfpDefines::TableType::PRODUCTION : RimVfpDefines::TableType::INJECTION;
m_tableNumber = table.tableNumber;
m_referenceDepth = table.datumDepth;
m_flowingPhase = table.flowingPhase;
m_flowingGasFraction = table.gasFraction;
m_flowingWaterFraction = table.waterFraction;
}
size_t numFamilyValues = getProductionTableData( table, familyVariable ).size();
for ( size_t familyIdx = 0; familyIdx < numFamilyValues; familyIdx++ )
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const RigVfpTables* RimVfpPlot::vfpTables() const
{
if ( m_vfpTableData )
{
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 );
size_t gfr_idx =
getVariableIndex( table, RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO, primaryVariable, y, familyVariable, familyIdx );
size_t alq_idx = getVariableIndex( table,
RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY,
primaryVariable,
y,
familyVariable,
familyIdx );
size_t flo_idx =
getVariableIndex( table, RimVfpDefines::ProductionVariableType::FLOW_RATE, primaryVariable, y, familyVariable, familyIdx );
size_t thp_idx =
getVariableIndex( table, RimVfpDefines::ProductionVariableType::THP, primaryVariable, y, familyVariable, familyIdx );
yVals[y] = table( thp_idx, wfr_idx, gfr_idx, alq_idx, flo_idx );
if ( m_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 );
m_vfpTableData->ensureDataIsImported();
return m_vfpTableData->vfpTables();
}
if ( m_vfpTables )
{
return m_vfpTables.get();
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
@ -868,64 +734,12 @@ QString RimVfpPlot::getDisplayUnit( RimVfpDefines::ProductionVariableType variab
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<double> RimVfpPlot::getProductionTableData( const Opm::VFPProdTable& table, RimVfpDefines::ProductionVariableType variableType ) const
{
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;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RimVfpPlot::getVariableIndex( const Opm::VFPProdTable& table,
RimVfpDefines::ProductionVariableType targetVariable,
RimVfpDefines::ProductionVariableType primaryVariable,
size_t primaryValue,
RimVfpDefines::ProductionVariableType familyVariable,
size_t familyValue ) const
{
if ( targetVariable == primaryVariable ) return primaryValue;
if ( targetVariable == familyVariable ) return familyValue;
if ( targetVariable == RimVfpDefines::ProductionVariableType::WATER_CUT ) return m_waterCutIdx;
if ( targetVariable == RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO ) return m_gasLiquidRatioIdx;
if ( targetVariable == RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY ) return m_articifialLiftQuantityIdx;
if ( targetVariable == RimVfpDefines::ProductionVariableType::FLOW_RATE ) return m_flowRateIdx;
if ( targetVariable == RimVfpDefines::ProductionVariableType::THP ) return m_thpIdx;
return getProductionTableData( table, targetVariable ).size() - 1;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
uiOrdering.add( &m_filePath );
m_filePath.uiCapability()->setUiReadOnly( m_dataIsImportedExternally );
uiOrdering.add( &m_vfpTableData );
uiOrdering.add( &m_tableType );
uiOrdering.add( &m_tableNumber );
@ -999,89 +813,26 @@ QList<caf::PdmOptionItemInfo> RimVfpPlot::calculateValueOptions( const caf::PdmF
calculateTableValueOptions( RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO, options );
}
else if ( fieldNeedingOptions == &m_vfpTableData )
{
RimVfpDataCollection* vfpDataCollection = RimVfpDataCollection::instance();
for ( auto table : vfpDataCollection->vfpTableData() )
{
options.push_back( caf::PdmOptionItemInfo( table->name(), table ) );
}
}
return options;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpDefines::FlowingPhaseType RimVfpPlot::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 RimVfpPlot::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::FlowingGasFractionType RimVfpPlot::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;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpDefines::FlowingWaterFractionType RimVfpPlot::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;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::calculateTableValueOptions( RimVfpDefines::ProductionVariableType variableType, QList<caf::PdmOptionItemInfo>& options )
{
if ( m_prodTable )
if ( vfpTables() )
{
std::vector<double> values = getProductionTableData( *m_prodTable, variableType );
auto values = vfpTables()->getProductionTableData( m_tableNumber(), variableType );
for ( size_t i = 0; i < values.size(); i++ )
{
@ -1098,10 +849,32 @@ void RimVfpPlot::calculateTableValueOptions( RimVfpDefines::ProductionVariableTy
void RimVfpPlot::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
{
RimPlot::fieldChangedByUi( changedField, oldValue, newValue );
loadDataAndUpdate();
updateLayout();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::initAfterRead()
{
auto filePath = m_filePath_OBSOLETE.v().path();
if ( filePath.isEmpty() ) return;
QString fileName = RimProject::current()->updatedFilePathFromPathId( filePath );
auto vfpDataCollection = RimVfpDataCollection::instance();
if ( vfpDataCollection )
{
auto tableData = vfpDataCollection->appendTableDataObject( fileName );
if ( tableData )
{
setDataSource( tableData );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -1143,3 +916,22 @@ caf::PdmFieldHandle* RimVfpPlot::userDescriptionField()
{
return &m_plotTitle;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::scheduleReplot()
{
if ( m_plotWidget )
{
m_plotWidget->scheduleReplot();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
VfpTableSelection RimVfpPlot::tableSelection() const
{
return { m_flowRateIdx(), m_thpIdx(), m_articifialLiftQuantityIdx(), m_waterCutIdx(), m_gasLiquidRatioIdx() };
}

View File

@ -22,15 +22,24 @@
#include "RimVfpDefines.h"
#include "cafFilePath.h"
#include "cafPdmPtrField.h"
#include <QPointer>
#include "opm/input/eclipse/Schedule/VFPInjTable.hpp"
#include "opm/input/eclipse/Schedule/VFPProdTable.hpp"
class RiuPlotWidget;
class VfpPlotData;
class RimPlotAxisProperties;
class RigVfpTables;
class RimVfpTableData;
struct VfpTableSelection;
struct VfpTableInitialData;
namespace Opm
{
class VFPInjTable;
class VFPProdTable;
} // namespace Opm
//--------------------------------------------------------------------------------------------------
/// Vertical Flow Performance Plot
@ -43,7 +52,9 @@ public:
RimVfpPlot();
~RimVfpPlot() override;
void setFileName( const QString& filename );
void setDataSource( RimVfpTableData* vfpTableData );
void setTableNumber( int tableNumber );
void initializeObject();
// RimPlot implementations
RiuPlotWidget* plotWidget() override;
@ -65,43 +76,30 @@ public:
QImage snapshotWindowContent() override;
void zoomAll() override;
void setProductionTable( const Opm::VFPProdTable& table );
void setInjectionTable( const Opm::VFPInjTable& table );
void setDataIsImportedExternally( bool dataIsImportedExternally );
int tableNumber() const;
private:
// RimPlot implementations
void doRemoveFromCollection();
// RimViewWindow implementations
void onChildrenUpdated( caf::PdmChildArrayFieldHandle* childArray, std::vector<caf::PdmObjectHandle*>& updatedObjects ) override;
void deleteViewWidget() override;
void onLoadDataAndUpdate() override;
// PDM methods
caf::PdmFieldHandle* userDescriptionField() override;
void scheduleReplot();
private:
RiuPlotWidget* doCreatePlotViewWidget( QWidget* mainWindowParent ) override;
void populatePlotWidgetWithCurveData( RiuPlotWidget* plotWidget, const Opm::VFPInjTable& table );
void populatePlotWidgetWithCurveData( RiuPlotWidget* plotWidget,
const Opm::VFPProdTable& table,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable );
std::vector<double> getProductionTableData( const Opm::VFPProdTable& table, RimVfpDefines::ProductionVariableType variableType ) const;
size_t getVariableIndex( const Opm::VFPProdTable& table,
RimVfpDefines::ProductionVariableType targetVariable,
RimVfpDefines::ProductionVariableType primaryVariable,
size_t primaryValue,
RimVfpDefines::ProductionVariableType familyVariable,
size_t familyValue ) const;
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;
VfpTableSelection tableSelection() const;
void initializeFromInitData( const VfpTableInitialData& table );
const RigVfpTables* vfpTables() const;
RiuPlotWidget* doCreatePlotViewWidget( QWidget* mainWindowParent ) override;
void calculateTableValueOptions( RimVfpDefines::ProductionVariableType variableType, QList<caf::PdmOptionItemInfo>& options );
void setFixedVariableUiEditability( caf::PdmField<int>& field, RimVfpDefines::ProductionVariableType variableType );
@ -114,30 +112,11 @@ 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 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 );
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 );
void populatePlotData( const Opm::VFPProdTable& table,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase,
VfpPlotData& plotData ) const;
static void populatePlotData( const Opm::VFPInjTable& table,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase,
VfpPlotData& plotData );
void populatePlotWidgetWithPlotData( RiuPlotWidget* plotWidget, const VfpPlotData& plotData );
static QString axisTitle( RimVfpDefines::ProductionVariableType variableType, RimVfpDefines::FlowingPhaseType flowingPhase );
@ -149,10 +128,11 @@ private:
void updateAxisRangesFromPlotWidget() override;
void onPlotZoomed();
void curveAppearanceChanged( const caf::SignalEmitter* emitter );
private:
caf::PdmField<QString> m_plotTitle;
caf::PdmField<caf::FilePath> m_filePath;
caf::PdmPtrField<RimVfpTableData*> m_vfpTableData;
caf::PdmField<int> m_tableNumber;
caf::PdmField<double> m_referenceDepth;
caf::PdmField<caf::AppEnum<RimVfpDefines::FlowingPhaseType>> m_flowingPhase;
@ -173,9 +153,12 @@ private:
caf::PdmChildField<RimPlotAxisProperties*> m_yAxisProperties;
caf::PdmChildField<RimPlotAxisProperties*> m_xAxisProperties;
QPointer<RiuPlotWidget> m_plotWidget;
std::unique_ptr<Opm::VFPProdTable> m_prodTable;
std::unique_ptr<Opm::VFPInjTable> m_injectionTable;
caf::PdmChildArrayField<RimPlotCurve*> m_plotCurves;
QPointer<RiuPlotWidget> m_plotWidget;
std::unique_ptr<RigVfpTables> m_vfpTables;
caf::PdmField<caf::FilePath> m_filePath_OBSOLETE;
bool m_dataIsImportedExternally;
};

View File

@ -18,16 +18,8 @@
#include "RimVfpPlotCollection.h"
#include "RiaApplication.h"
#include "RigCaseCellResultsData.h"
#include "RigEclipseCaseData.h"
#include "RigEclipseResultAddress.h"
#include "RigEquil.h"
#include "RimEclipseResultCase.h"
#include "RimProject.h"
#include "RimVfpDeck.h"
#include "RimVfpTableData.h"
#include "cafCmdFeatureMenuBuilder.h"
@ -47,8 +39,43 @@ RimVfpPlotCollection::RimVfpPlotCollection()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpPlotCollection::~RimVfpPlotCollection()
RimVfpPlot* RimVfpPlotCollection::createAndAppendPlots( RimVfpTableData* tableData )
{
if ( !tableData ) return nullptr;
tableData->ensureDataIsImported();
if ( !tableData->vfpTables() ) return nullptr;
RimVfpPlot* firstPlot = nullptr;
if ( tableData->tableCount() > 1 )
{
auto* deck = new RimVfpDeck();
deck->setDataSource( tableData );
addDeck( deck );
deck->loadDataAndUpdate();
deck->updateAllRequiredEditors();
auto plots = deck->plots();
if ( !plots.empty() )
{
firstPlot = plots.front();
}
}
else
{
auto vfpPlot = new RimVfpPlot();
vfpPlot->setDataSource( tableData );
vfpPlot->initializeObject();
addPlot( vfpPlot );
vfpPlot->loadDataAndUpdate();
firstPlot = vfpPlot;
}
return firstPlot;
}
//--------------------------------------------------------------------------------------------------
@ -75,14 +102,6 @@ std::vector<RimVfpPlot*> RimVfpPlotCollection::plots() const
return m_vfpPlots.childrenByType();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlotCollection::deleteChildren()
{
m_vfpPlots.deleteChildren();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -119,13 +138,30 @@ void RimVfpPlotCollection::removePlot( RimVfpPlot* vfpPlot )
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpDeck* RimVfpPlotCollection::addDeck( const QString& filename )
void RimVfpPlotCollection::addDeck( RimVfpDeck* deck )
{
RimVfpDeck* deck = new RimVfpDeck();
deck->setFileName( filename );
m_vfpDecks.push_back( deck );
}
return deck;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlotCollection::deleteAllPlots()
{
m_vfpPlots.deleteChildren();
m_vfpDecks.deleteChildren();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlotCollection::addImportItems( caf::CmdFeatureMenuBuilder& menuBuilder )
{
// A variant with a true value is used to indicate that the VFP data is imported from a file
// This is used to distinguish between VFP data imported from a file and VFP data imported from a simulator
QVariant variant( QVariant::fromValue( true ) );
menuBuilder.addCmdFeatureWithUserData( "RicImportVfpDataFeature", "Import VFP Files", variant );
menuBuilder.addCmdFeature( "RicImportVfpDataFeature", "Import VFP from Simulator Files" );
}
//--------------------------------------------------------------------------------------------------
@ -160,9 +196,5 @@ void RimVfpPlotCollection::loadDataAndUpdateAllPlots()
//--------------------------------------------------------------------------------------------------
void RimVfpPlotCollection::appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const
{
// A variant with a true value is used to indicate that the VFP data is imported from a file
// This is used to distinguish between VFP data imported from a file and VFP data imported from a simulator
QVariant variant( QVariant::fromValue( true ) );
menuBuilder.addCmdFeatureWithUserData( "RicImportVfpDataFeature", "Import VFP Files", variant );
menuBuilder.addCmdFeature( "RicImportVfpDataFeature", "Import VFP from Simulator Files" );
addImportItems( menuBuilder );
}

View File

@ -35,18 +35,19 @@ class RimVfpPlotCollection : public caf::PdmObject, public RimTypedPlotCollectio
public:
RimVfpPlotCollection();
~RimVfpPlotCollection() override;
RimVfpPlot* createAndAppendPlots( RimVfpTableData* tableData );
RimVfpPlot* plotForTableNumber( int tableNumber ) const;
void addPlot( RimVfpPlot* newPlot ) override;
std::vector<RimVfpPlot*> plots() const override;
void deleteChildren();
RimVfpPlot* plotForTableNumber( int tableNumber ) const;
size_t plotCount() const final;
void insertPlot( RimVfpPlot* vfpPlot, size_t index ) final;
void removePlot( RimVfpPlot* vfpPlot ) final;
void deleteAllPlots() override;
RimVfpDeck* addDeck( const QString& filename );
static void addImportItems( caf::CmdFeatureMenuBuilder& menuBuilder );
private:
void loadDataAndUpdateAllPlots() override;
@ -54,6 +55,8 @@ private:
void appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const override;
void addDeck( RimVfpDeck* deck );
private:
caf::PdmChildArrayField<RimVfpPlot*> m_vfpPlots;
caf::PdmChildArrayField<RimVfpDeck*> m_vfpDecks;

View File

@ -0,0 +1,126 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 "RimVfpTableData.h"
#include "RiaOpmParserTools.h"
#include "RigVfpTables.h"
#include "cafCmdFeatureMenuBuilder.h"
#include <QFileInfo>
CAF_PDM_SOURCE_INIT( RimVfpTableData, "RimVfpTableData" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpTableData::RimVfpTableData()
{
CAF_PDM_InitObject( "VFP Plot", ":/VfpPlot.svg" );
CAF_PDM_InitFieldNoDefault( &m_filePath, "FilePath", "File Path" );
setDeletable( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpTableData::setFileName( const QString& filename )
{
m_filePath = filename;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimVfpTableData::baseFileName()
{
QFileInfo fileInfo( m_filePath().path() );
return fileInfo.baseName();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpTableData::ensureDataIsImported()
{
if ( m_vfpTables ) return;
updateObjectName();
m_vfpTables = std::make_unique<RigVfpTables>();
const auto [vfpProdTables, vfpInjTables] = RiaOpmParserTools::extractVfpTablesFromDataFile( m_filePath().path().toStdString() );
for ( const auto& prod : vfpProdTables )
{
m_vfpTables->addProductionTable( prod );
}
for ( const auto& inj : vfpInjTables )
{
m_vfpTables->addInjectionTable( inj );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RimVfpTableData::tableCount() const
{
if ( m_vfpTables )
{
return m_vfpTables->injectionTableNumbers().size() + m_vfpTables->productionTableNumbers().size();
}
return 0;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const RigVfpTables* RimVfpTableData::vfpTables() const
{
return m_vfpTables.get();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpTableData::updateObjectName()
{
QString name = "VFP Plots";
QFileInfo fileInfo( m_filePath().path() );
auto fileName = fileInfo.fileName();
if ( !fileName.isEmpty() )
{
name = fileName;
}
setName( name );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpTableData::appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const
{
menuBuilder << "RicNewVfpPlotFeature";
}

View File

@ -0,0 +1,55 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RimNamedObject.h"
#include "cafFilePath.h"
#include <memory>
class RigVfpTables;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
class RimVfpTableData : public RimNamedObject
{
CAF_PDM_HEADER_INIT;
public:
RimVfpTableData();
void setFileName( const QString& filename );
QString baseFileName();
void ensureDataIsImported();
size_t tableCount() const;
const RigVfpTables* vfpTables() const;
private:
void updateObjectName();
void appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const override;
private:
caf::PdmField<caf::FilePath> m_filePath;
std::unique_ptr<RigVfpTables> m_vfpTables;
};

View File

@ -98,6 +98,7 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RigWellResultBranch.h
${CMAKE_CURRENT_LIST_DIR}/RigWellResultFrame.h
${CMAKE_CURRENT_LIST_DIR}/RigReservoirBuilder.h
${CMAKE_CURRENT_LIST_DIR}/RigVfpTables.h
)
set(SOURCE_GROUP_SOURCE_FILES
@ -194,6 +195,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RigWellResultFrame.cpp
${CMAKE_CURRENT_LIST_DIR}/RigDeclineCurveCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RigReservoirBuilder.cpp
${CMAKE_CURRENT_LIST_DIR}/RigVfpTables.cpp
)
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})

View File

@ -0,0 +1,569 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
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 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
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;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
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 {};
}

View File

@ -0,0 +1,157 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "VerticalFlowPerformance/RimVfpDefines.h"
#include <QString>
#include <optional>
#include <vector>
namespace Opm
{
class VFPInjTable;
class VFPProdTable;
} // namespace Opm
class VfpPlotData
{
public:
void setXAxisTitle( const QString& xAxisTitle ) { m_xAxisTitle = xAxisTitle; }
void setYAxisTitle( const QString& yAxisTitle ) { m_yAxisTitle = yAxisTitle; }
const QString& xAxisTitle() const { return m_xAxisTitle; }
const QString& yAxisTitle() const { return m_yAxisTitle; }
void appendCurve( const QString& curveTitle, const std::vector<double>& xData, const std::vector<double>& yData )
{
m_curveTitles.push_back( curveTitle );
m_xData.push_back( xData );
m_yData.push_back( yData );
}
const QString& curveTitle( size_t idx ) const { return m_curveTitles[idx]; }
size_t size() const { return m_xData.size(); }
size_t curveSize( size_t idx ) const { return m_xData[idx].size(); }
const std::vector<double>& xData( size_t idx ) const { return m_xData[idx]; }
const std::vector<double>& yData( size_t idx ) const { return m_yData[idx]; }
private:
QString m_xAxisTitle;
QString m_yAxisTitle;
std::vector<QString> m_curveTitles;
std::vector<std::vector<double>> m_xData;
std::vector<std::vector<double>> m_yData;
};
struct VfpTableSelection
{
int flowRateIdx;
int thpIdx;
int articifialLiftQuantityIdx;
int waterCutIdx;
int gasLiquidRatioIdx;
};
struct VfpTableInitialData
{
bool isProductionTable;
int tableNumber;
double datumDepth;
RimVfpDefines::FlowingPhaseType flowingPhase;
RimVfpDefines::FlowingWaterFractionType waterFraction;
RimVfpDefines::FlowingGasFractionType gasFraction;
};
//==================================================================================================
///
//==================================================================================================
class RigVfpTables
{
public:
void addInjectionTable( const Opm::VFPInjTable& table );
void addProductionTable( const Opm::VFPProdTable& table );
std::vector<int> injectionTableNumbers() const;
std::vector<int> productionTableNumbers() const;
VfpTableInitialData getTableInitialData( int tableIndex ) const;
std::vector<double> getProductionTableData( int tableIndex, RimVfpDefines::ProductionVariableType variableType ) const;
VfpPlotData populatePlotData( int tableIndex,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase,
const VfpTableSelection& tableSelection ) const;
QString asciiDataForTable( int tableNumber,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase,
const VfpTableSelection& tableSelection ) const;
private:
static VfpPlotData populatePlotData( const Opm::VFPInjTable& table,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase );
static VfpPlotData populatePlotData( const Opm::VFPProdTable& table,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase,
const VfpTableSelection& tableSelection );
static QString axisTitle( RimVfpDefines::ProductionVariableType variableType, RimVfpDefines::FlowingPhaseType flowingPhase );
static QString getDisplayUnit( RimVfpDefines::ProductionVariableType variableType );
static QString getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType variableType );
static double convertToDisplayUnit( double value, RimVfpDefines::ProductionVariableType variableType );
static void convertToDisplayUnit( std::vector<double>& values, RimVfpDefines::ProductionVariableType variableType );
static QString textForPlotData( const VfpPlotData& plotData );
static std::vector<double> getProductionTableData( const Opm::VFPProdTable& table, RimVfpDefines::ProductionVariableType variableType );
static size_t getVariableIndex( const Opm::VFPProdTable& table,
RimVfpDefines::ProductionVariableType targetVariable,
RimVfpDefines::ProductionVariableType primaryVariable,
size_t primaryValue,
RimVfpDefines::ProductionVariableType familyVariable,
size_t familyValue,
const VfpTableSelection& tableSelection );
std::optional<Opm::VFPInjTable> injectionTable( int tableNumber ) const;
std::optional<Opm::VFPProdTable> 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 );
private:
std::vector<Opm::VFPInjTable> m_injectionTables;
std::vector<Opm::VFPProdTable> m_productionTables;
};