Custom vfp plot (#11450)

* AppFwk: When clearing a tree selection, make sure all values are cleared
* Fix deprecated implicit lambda
* Add support for using the closest value in addition to exact match
* Add table data source object and add plot with multiple data sources
Delete the temporary RimVfpDeck class
Add RimVfpTable to represent a table in a data source
Add plot able to show data from multiple tables

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

* Call resolveReferencesRecursively() after RimVfpTable objects are created
This commit is contained in:
Magne Sjaastad 2024-05-29 12:55:45 +02:00 committed by GitHub
parent 2fb54ac1ec
commit 1d57b9032b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 2206 additions and 375 deletions

View File

@ -92,6 +92,8 @@
#include "RimWellPath.h"
#include "RimWellPathCollection.h"
#include "RimWellPathFracture.h"
#include "VerticalFlowPerformance/RimVfpDataCollection.h"
#include "VerticalFlowPerformance/RimVfpPlotCollection.h"
#include "Riu3DMainWindowTools.h"
#include "RiuGuiTheme.h"
@ -539,6 +541,7 @@ bool RiaApplication::loadProject( const QString& projectFileName, ProjectLoadAct
// Initialize well paths
oilField->wellPathCollection->loadDataAndUpdate();
oilField->ensembleWellLogsCollection->loadDataAndUpdate();
oilField->vfpDataCollection->loadDataAndUpdate();
// Initialize seismic data
auto& seisDataColl = oilField->seismicDataCollection();
@ -553,6 +556,10 @@ bool RiaApplication::loadProject( const QString& projectFileName, ProjectLoadAct
{
RimMainPlotCollection* mainPlotColl = RimMainPlotCollection::current();
mainPlotColl->ensureDefaultFlowPlotsAreCreated();
// RimVfpTable are not presisted in the project file, and are created in vfpDataCollection->loadDataAndUpdate(). Existing VFP
// plots will have references to RimVfpTables. Call resolveReferencesRecursively() to update the references to RimVfpTable objects.
mainPlotColl->vfpPlotCollection()->resolveReferencesRecursively();
}
for ( RimOilField* oilField : m_project->oilFields )

View File

@ -25,7 +25,7 @@ void RiaFileDownloader::downloadFile( const QUrl& url, const QString& filePath )
connect( reply,
&QNetworkReply::finished,
[=]()
[=, this]()
{
if ( reply->error() )
{

View File

@ -96,6 +96,7 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RicImportWellLogCsvFileFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicNewViewForGridEnsembleFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicNewVfpPlotFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicNewCustomVfpPlotFeature.h
)
set(SOURCE_GROUP_SOURCE_FILES
@ -195,6 +196,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RicImportWellLogCsvFileFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewViewForGridEnsembleFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewVfpPlotFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewCustomVfpPlotFeature.cpp
)
if(RESINSIGHT_USE_QT_CHARTS)

View File

@ -26,6 +26,8 @@
#include "RimWellPathFracture.h"
#include "RimWellPathFractureCollection.h"
#include "VerticalFlowPerformance/RimVfpDataCollection.h"
#include "cafPdmUiItem.h"
#include "cafPdmUiObjectHandle.h"
#include "cafSelectionManager.h"
@ -124,6 +126,11 @@ bool RicDeleteSubItemsFeature::hasDeletableSubItems( caf::PdmUiItem* uiItem )
}
}
if ( dynamic_cast<RimVfpDataCollection*>( uiItem ) )
{
return true;
}
return false;
}
@ -141,113 +148,108 @@ void RicDeleteSubItemsFeature::deleteSubItems( bool onlyDeleteUnchecked )
{
if ( !RicDeleteSubItemsFeature::hasDeletableSubItems( item ) ) continue;
if ( auto multiPlot = dynamic_cast<RimSummaryMultiPlot*>( item ) )
{
auto multiPlot = dynamic_cast<RimSummaryMultiPlot*>( item );
if ( multiPlot )
if ( onlyDeleteUnchecked )
{
if ( onlyDeleteUnchecked )
auto plots = multiPlot->plots();
for ( auto plot : plots )
{
auto plots = multiPlot->plots();
for ( auto plot : plots )
{
if ( plot->showWindow() ) continue;
multiPlot->removePlotNoUpdate( plot );
delete plot;
}
if ( plot->showWindow() ) continue;
multiPlot->removePlotNoUpdate( plot );
delete plot;
}
else
{
multiPlot->deleteAllPlots();
}
multiPlot->updateConnectedEditors();
}
else
{
multiPlot->deleteAllPlots();
}
multiPlot->updateConnectedEditors();
}
if ( auto collection = dynamic_cast<RimSummaryMultiPlotCollection*>( item ) )
{
auto collection = dynamic_cast<RimSummaryMultiPlotCollection*>( item );
if ( collection )
if ( onlyDeleteUnchecked )
{
if ( onlyDeleteUnchecked )
auto plots = collection->multiPlots();
for ( auto plot : plots )
{
auto plots = collection->multiPlots();
for ( auto plot : plots )
{
if ( plot->showWindow() ) continue;
collection->removePlotNoUpdate( plot );
delete plot;
}
if ( plot->showWindow() ) continue;
collection->removePlotNoUpdate( plot );
delete plot;
}
else
{
collection->deleteAllPlots();
}
collection->updateConnectedEditors();
}
}
{
auto collection = dynamic_cast<RimWellPathCollection*>( item );
if ( collection )
{
if ( onlyDeleteUnchecked )
{
auto paths = collection->allWellPaths();
for ( auto path : paths )
{
if ( path->showWellPath() ) continue;
collection->removeWellPath( path );
delete path;
}
}
else
{
collection->deleteAllWellPaths();
}
collection->updateConnectedEditors();
collection->scheduleRedrawAffectedViews();
}
}
{
auto collection = dynamic_cast<RimWellPathFractureCollection*>( item );
if ( collection )
{
if ( onlyDeleteUnchecked )
{
auto items = collection->allFractures();
for ( auto item : items )
{
if ( item->isChecked() ) continue;
collection->removeFracture( item );
delete item;
}
}
else
{
collection->deleteFractures();
}
collection->updateConnectedEditors();
RimProject* proj = RimProject::current();
if ( proj ) proj->reloadCompletionTypeResultsInAllViews();
}
}
{
auto collection = dynamic_cast<RimPlotCollection*>( item );
if ( collection )
else
{
collection->deleteAllPlots();
}
if ( auto objHandle = dynamic_cast<caf::PdmUiObjectHandle*>( item ) )
collection->updateConnectedEditors();
}
if ( auto collection = dynamic_cast<RimWellPathCollection*>( item ) )
{
if ( onlyDeleteUnchecked )
{
auto paths = collection->allWellPaths();
for ( auto path : paths )
{
objHandle->updateConnectedEditors();
if ( path->showWellPath() ) continue;
collection->removeWellPath( path );
delete path;
}
}
else
{
collection->deleteAllWellPaths();
}
collection->updateConnectedEditors();
collection->scheduleRedrawAffectedViews();
}
if ( auto collection = dynamic_cast<RimWellPathFractureCollection*>( item ) )
{
if ( onlyDeleteUnchecked )
{
auto items = collection->allFractures();
for ( auto item : items )
{
if ( item->isChecked() ) continue;
collection->removeFracture( item );
delete item;
}
}
else
{
collection->deleteFractures();
}
collection->updateConnectedEditors();
RimProject* proj = RimProject::current();
if ( proj ) proj->reloadCompletionTypeResultsInAllViews();
}
if ( auto collection = dynamic_cast<RimPlotCollection*>( item ) )
{
collection->deleteAllPlots();
if ( auto objHandle = dynamic_cast<caf::PdmUiObjectHandle*>( item ) )
{
objHandle->updateConnectedEditors();
}
}
if ( auto collection = dynamic_cast<RimVfpDataCollection*>( item ) )
{
collection->deleteAllData();
if ( auto objHandle = dynamic_cast<caf::PdmUiObjectHandle*>( item ) )
{
objHandle->updateConnectedEditors();
}
}
}
}

View File

@ -24,7 +24,6 @@
#include "RimMainPlotCollection.h"
#include "VerticalFlowPerformance/RimVfpDataCollection.h"
#include "VerticalFlowPerformance/RimVfpDeck.h"
#include "VerticalFlowPerformance/RimVfpPlot.h"
#include "VerticalFlowPerformance/RimVfpPlotCollection.h"
@ -72,9 +71,6 @@ void RicImportVfpDataFeature::onActionTriggered( bool isChecked )
app->setLastUsedDialogDirectory( vfpDataKey, QFileInfo( fileNames.last() ).absolutePath() );
std::vector<RimVfpPlot*> vfpPlots;
std::vector<RimVfpDeck*> vfpDecks;
auto vfpDataColl = RimVfpDataCollection::instance();
for ( const auto& fileName : fileNames )

View File

@ -0,0 +1,66 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 "RicNewCustomVfpPlotFeature.h"
#include "RicNewVfpPlotFeature.h"
#include "RimMainPlotCollection.h"
#include "VerticalFlowPerformance/RimCustomVfpPlot.h"
#include "VerticalFlowPerformance/RimVfpDataCollection.h"
#include "VerticalFlowPerformance/RimVfpPlotCollection.h"
#include "VerticalFlowPerformance/RimVfpTable.h"
#include "VerticalFlowPerformance/RimVfpTableData.h"
#include "cafSelectionManagerTools.h"
#include "RiuPlotMainWindowTools.h"
#include <QAction>
CAF_CMD_SOURCE_INIT( RicNewCustomVfpPlotFeature, "RicNewCustomVfpPlotFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicNewCustomVfpPlotFeature::onActionTriggered( bool isChecked )
{
RimVfpPlotCollection* vfpPlotColl = RimMainPlotCollection::current()->vfpPlotCollection();
if ( !vfpPlotColl ) return;
auto selectedTables = RicNewVfpPlotFeature::selectedTables();
if ( selectedTables.empty() ) return;
auto mainDataSource = selectedTables.front();
std::vector<RimVfpTable*> additionalDataSources;
std::copy( selectedTables.begin() + 1, selectedTables.end(), std::back_inserter( additionalDataSources ) );
auto firstPlot = vfpPlotColl->createAndAppendPlots( mainDataSource, additionalDataSources );
vfpPlotColl->updateConnectedEditors();
RiuPlotMainWindowTools::onObjectAppended( firstPlot, firstPlot );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicNewCustomVfpPlotFeature::setupActionLook( QAction* actionToSetup )
{
actionToSetup->setText( "Create Custom 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 RicNewCustomVfpPlotFeature : public caf::CmdFeature
{
CAF_CMD_HEADER_INIT;
private:
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;
};

View File

@ -22,6 +22,7 @@
#include "VerticalFlowPerformance/RimVfpDataCollection.h"
#include "VerticalFlowPerformance/RimVfpPlotCollection.h"
#include "VerticalFlowPerformance/RimVfpTable.h"
#include "VerticalFlowPerformance/RimVfpTableData.h"
#include "cafSelectionManagerTools.h"
@ -32,6 +33,22 @@
CAF_CMD_SOURCE_INIT( RicNewVfpPlotFeature, "RicNewVfpPlotFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimVfpTable*> RicNewVfpPlotFeature::selectedTables()
{
auto tables = caf::selectedObjectsByTypeStrict<RimVfpTable*>();
auto selectedTableData = caf::selectedObjectsByTypeStrict<RimVfpTableData*>();
for ( auto tableData : selectedTableData )
{
auto tableDataSources = tableData->tableDataSources();
tables.insert( tables.end(), tableDataSources.begin(), tableDataSources.end() );
}
return tables;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -40,10 +57,9 @@ void RicNewVfpPlotFeature::onActionTriggered( bool isChecked )
RimVfpPlotCollection* vfpPlotColl = RimMainPlotCollection::current()->vfpPlotCollection();
if ( !vfpPlotColl ) return;
auto selectedTableData = caf::selectedObjectsByTypeStrict<RimVfpTableData*>();
for ( auto tableData : selectedTableData )
for ( auto table : selectedTables() )
{
RimVfpPlot* firstPlot = vfpPlotColl->createAndAppendPlots( tableData );
RimVfpPlot* firstPlot = vfpPlotColl->createAndAppendPlots( table );
vfpPlotColl->updateConnectedEditors();
RiuPlotMainWindowTools::onObjectAppended( firstPlot, firstPlot );
}

View File

@ -20,6 +20,8 @@
#include "cafCmdFeature.h"
class RimVfpTable;
//==================================================================================================
///
//==================================================================================================
@ -27,6 +29,9 @@ class RicNewVfpPlotFeature : public caf::CmdFeature
{
CAF_CMD_HEADER_INIT;
public:
static std::vector<RimVfpTable*> selectedTables();
private:
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;

View File

@ -1,18 +1,20 @@
set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RimVfpDefines.h
${CMAKE_CURRENT_LIST_DIR}/RimVfpDeck.h
${CMAKE_CURRENT_LIST_DIR}/RimVfpPlot.h
${CMAKE_CURRENT_LIST_DIR}/RimCustomVfpPlot.h
${CMAKE_CURRENT_LIST_DIR}/RimVfpPlotCollection.h
${CMAKE_CURRENT_LIST_DIR}/RimVfpTableData.h
${CMAKE_CURRENT_LIST_DIR}/RimVfpTable.h
${CMAKE_CURRENT_LIST_DIR}/RimVfpDataCollection.h
)
set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RimVfpDeck.cpp
${CMAKE_CURRENT_LIST_DIR}/RimVfpDefines.cpp
${CMAKE_CURRENT_LIST_DIR}/RimVfpPlot.cpp
${CMAKE_CURRENT_LIST_DIR}/RimCustomVfpPlot.cpp
${CMAKE_CURRENT_LIST_DIR}/RimVfpPlotCollection.cpp
${CMAKE_CURRENT_LIST_DIR}/RimVfpTableData.cpp
${CMAKE_CURRENT_LIST_DIR}/RimVfpTable.cpp
${CMAKE_CURRENT_LIST_DIR}/RimVfpDataCollection.cpp
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,172 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 "RimPlot.h"
#include "RimVfpDefines.h"
#include "cafPdmPtrArrayField.h"
#include "cafPdmPtrField.h"
#include <QPointer>
class RiuPlotWidget;
class VfpPlotData;
class RimPlotAxisProperties;
class RigVfpTables;
class RimVfpTableData;
class RimVfpTable;
class RiuPlotCurveInfoTextProvider;
struct VfpValueSelection;
struct VfpTableInitialData;
namespace Opm
{
class VFPInjTable;
class VFPProdTable;
} // namespace Opm
//--------------------------------------------------------------------------------------------------
/// Vertical Flow Performance Plot
//--------------------------------------------------------------------------------------------------
class RimCustomVfpPlot : public RimPlot
{
CAF_PDM_HEADER_INIT;
public:
RimCustomVfpPlot();
~RimCustomVfpPlot() override;
void selectDataSource( RimVfpTable* mainDataSource, const std::vector<RimVfpTable*>& vfpTableData );
void setTableNumber( int tableNumber );
void initializeObject();
// RimPlot implementations
RiuPlotWidget* plotWidget() override;
bool isCurveHighlightSupported() const override;
void setAutoScaleXEnabled( bool enabled ) override;
void setAutoScaleYEnabled( bool enabled ) override;
void updateAxes() override;
void updateLegend() override;
QString asciiDataForPlotExport() const override;
void reattachAllCurves() override;
void detachAllCurves() override;
// RimPlotWindow implementations
QString description() const override;
QString infoForCurve( RimPlotCurve* plotCurve ) const;
// RimViewWindow implementations
QWidget* viewWidget() override;
QImage snapshotWindowContent() override;
void zoomAll() override;
private:
void onChildrenUpdated( caf::PdmChildArrayFieldHandle* childArray, std::vector<caf::PdmObjectHandle*>& updatedObjects ) override;
void deleteViewWidget() override;
void onLoadDataAndUpdate() override;
caf::PdmFieldHandle* userDescriptionField() override;
void scheduleReplot();
private:
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
void initAfterRead() override;
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
VfpValueSelection tableSelection( RimVfpTable* table ) const;
void initializeFromInitData( const VfpTableInitialData& table );
RiuPlotWidget* doCreatePlotViewWidget( QWidget* mainWindowParent ) override;
void calculateTableValueOptions( RimVfpDefines::ProductionVariableType variableType, QList<caf::PdmOptionItemInfo>& options );
void setFixedVariableUiEditability( caf::PdmFieldHandle& field, RimVfpDefines::ProductionVariableType variableType );
void updatePlotTitle( const QString& plotTitle );
static QString generatePlotTitle( const QString& wellName,
int tableNumber,
RimVfpDefines::TableType tableType,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable );
static double convertToDisplayUnit( double value, RimVfpDefines::ProductionVariableType variableType );
static void convertToDisplayUnit( std::vector<double>& values, RimVfpDefines::ProductionVariableType variableType );
static QString getDisplayUnit( RimVfpDefines::ProductionVariableType variableType );
static QString getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType variableType );
void populatePlotWidgetWithPlotData( RiuPlotWidget* plotWidget, const VfpPlotData& plotData, const QColor& color );
static QString axisTitle( RimVfpDefines::ProductionVariableType variableType, RimVfpDefines::FlowingPhaseType flowingPhase );
void connectAxisSignals( RimPlotAxisProperties* axis );
void axisSettingsChanged( const caf::SignalEmitter* emitter );
void axisLogarithmicChanged( const caf::SignalEmitter* emitter, bool isLogarithmic );
void updatePlotWidgetFromAxisRanges() override;
void updateAxisRangesFromPlotWidget() override;
void onPlotZoomed();
void curveAppearanceChanged( const caf::SignalEmitter* emitter );
std::vector<double> availableValues( RimVfpDefines::ProductionVariableType variableType ) const;
static RiuPlotCurveInfoTextProvider* curveTextProvider();
private:
caf::PdmField<QString> m_plotTitle;
caf::PdmPtrField<RimVfpTable*> m_mainDataSource;
caf::PdmPtrArrayField<RimVfpTable*> m_additionalDataSources;
caf::PdmField<caf::AppEnum<RimVfpDefines::CurveMatchingType>> m_curveMatchingType;
caf::PdmField<caf::AppEnum<RimVfpDefines::CurveOptionValuesType>> m_curveOptionFiltering;
caf::PdmField<int> m_tableNumber;
caf::PdmField<double> m_referenceDepth;
caf::PdmField<caf::AppEnum<RimVfpDefines::FlowingPhaseType>> m_flowingPhase;
caf::PdmField<caf::AppEnum<RimVfpDefines::FlowingWaterFractionType>> m_flowingWaterFraction;
caf::PdmField<caf::AppEnum<RimVfpDefines::FlowingGasFractionType>> m_flowingGasFraction;
caf::PdmField<caf::AppEnum<RimVfpDefines::TableType>> m_tableType;
caf::PdmField<caf::AppEnum<RimVfpDefines::InterpolatedVariableType>> m_interpolatedVariable;
caf::PdmField<caf::AppEnum<RimVfpDefines::ProductionVariableType>> m_primaryVariable;
caf::PdmField<caf::AppEnum<RimVfpDefines::ProductionVariableType>> m_familyVariable;
caf::PdmField<double> m_flowRateIdx;
caf::PdmField<double> m_thpIdx;
caf::PdmField<double> m_articifialLiftQuantityIdx;
caf::PdmField<double> m_waterCutIdx;
caf::PdmField<double> m_gasLiquidRatioIdx;
caf::PdmField<std::vector<double>> m_familyValues;
caf::PdmChildField<RimPlotAxisProperties*> m_yAxisProperties;
caf::PdmChildField<RimPlotAxisProperties*> m_xAxisProperties;
caf::PdmChildArrayField<RimPlotCurve*> m_plotCurves;
std::vector<VfpPlotData> m_plotData;
QPointer<RiuPlotWidget> m_plotWidget;
};

View File

@ -46,22 +46,58 @@ RimVfpDataCollection* RimVfpDataCollection::instance()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpTableData* RimVfpDataCollection::appendTableDataObject( const QString& fileName )
RimVfpTable* RimVfpDataCollection::appendTableDataObject( const QString& fileName )
{
auto* vfpTableData = new RimVfpTableData();
vfpTableData->setFileName( fileName );
m_vfpTableData.push_back( vfpTableData );
return vfpTableData;
vfpTableData->ensureDataIsImported();
auto dataSources = vfpTableData->tableDataSources();
if ( !dataSources.empty() )
{
return dataSources.front();
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimVfpTableData*> RimVfpDataCollection::vfpTableData() const
std::vector<RimVfpTable*> RimVfpDataCollection::vfpTableData() const
{
return m_vfpTableData.childrenByType();
std::vector<RimVfpTable*> tableDataSources;
for ( auto vfpTableData : m_vfpTableData.childrenByType() )
{
for ( auto table : vfpTableData->tableDataSources() )
{
tableDataSources.push_back( table );
}
}
return tableDataSources;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpDataCollection::loadDataAndUpdate()
{
for ( auto vfpTableData : m_vfpTableData.childrenByType() )
{
vfpTableData->ensureDataIsImported();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpDataCollection::deleteAllData()
{
m_vfpTableData.deleteChildren();
}
//--------------------------------------------------------------------------------------------------

View File

@ -20,6 +20,7 @@
#include "cafPdmChildArrayField.h"
#include "cafPdmObject.h"
class RimVfpTable;
class RimVfpTableData;
//==================================================================================================
@ -35,8 +36,13 @@ public:
static RimVfpDataCollection* instance();
RimVfpTableData* appendTableDataObject( const QString& fileName );
std::vector<RimVfpTableData*> vfpTableData() const;
RimVfpTable* appendTableDataObject( const QString& fileName );
std::vector<RimVfpTable*> vfpTableData() const;
void loadDataAndUpdate();
void deleteAllData();
private:
void appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const override;

View File

@ -1,155 +0,0 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 "RimVfpDeck.h"
#include "RigVfpTables.h"
#include "RimVfpDataCollection.h"
#include "RimVfpPlotCollection.h"
#include "RimVfpTableData.h"
#include "cafPdmUiTreeOrdering.h"
CAF_PDM_SOURCE_INIT( RimVfpDeck, "RimVfpDeck" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpDeck::RimVfpDeck()
{
CAF_PDM_InitObject( "VFP Plot", ":/VfpPlot.svg" );
CAF_PDM_InitFieldNoDefault( &m_vfpTableData, "VfpTableData", "VFP Data Source" );
CAF_PDM_InitFieldNoDefault( &m_vfpPlotCollection, "VfpPlotCollection", "Plot Collection" );
m_vfpPlotCollection = new RimVfpPlotCollection();
setDeletable( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpDeck::setDataSource( RimVfpTableData* tableData )
{
m_vfpTableData = tableData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpDeck::loadDataAndUpdate()
{
updateObjectName();
std::vector<RimVfpPlot*> currentPlots = m_vfpPlotCollection->plots();
if ( m_vfpTableData )
{
m_vfpTableData->ensureDataIsImported();
if ( m_vfpTableData->vfpTables() )
{
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();
}
}
}
for ( auto plotToDelete : currentPlots )
{
m_vfpPlotCollection->removePlot( plotToDelete );
delete plotToDelete;
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimVfpPlot*> RimVfpDeck::plots() const
{
return m_vfpPlotCollection->plots();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpDeck::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName )
{
for ( auto p : m_vfpPlotCollection->plots() )
{
uiTreeOrdering.add( p );
}
uiTreeOrdering.skipRemainingChildren( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpDeck::updateObjectName()
{
QString name = "VFP Deck";
if ( m_vfpTableData )
{
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

@ -79,4 +79,20 @@ void caf::AppEnum<RimVfpDefines::FlowingGasFractionType>::setUp()
addItem( RimVfpDefines::FlowingGasFractionType::INVALID, "INVALID", "Invalid" );
setDefault( RimVfpDefines::FlowingGasFractionType::INVALID );
}
template <>
void caf::AppEnum<RimVfpDefines::CurveMatchingType>::setUp()
{
addItem( RimVfpDefines::CurveMatchingType::EXACT, "EXACT", "Exact" );
addItem( RimVfpDefines::CurveMatchingType::CLOSEST_MATCH_FAMILY, "CLOSEST_MATCH_FAMILY", "Family Closest Match" );
setDefault( RimVfpDefines::CurveMatchingType::EXACT );
}
template <>
void caf::AppEnum<RimVfpDefines::CurveOptionValuesType>::setUp()
{
addItem( RimVfpDefines::CurveOptionValuesType::MAIN_TABLE, "MAIN_TABLE", "Values from Main Table" );
addItem( RimVfpDefines::CurveOptionValuesType::UNION_OF_SELECTED_TABLES, "UNION_OF_SELECTED_TABLES", "Union of Selected Table Values" );
setDefault( RimVfpDefines::CurveOptionValuesType::MAIN_TABLE );
}
} // namespace caf

View File

@ -65,4 +65,17 @@ enum class FlowingGasFractionType
OGR,
INVALID
};
enum class CurveMatchingType
{
EXACT,
CLOSEST_MATCH_FAMILY,
};
enum class CurveOptionValuesType
{
MAIN_TABLE,
UNION_OF_SELECTED_TABLES,
};
}; // namespace RimVfpDefines

View File

@ -30,6 +30,7 @@
#include "RimProject.h"
#include "RimVfpDataCollection.h"
#include "RimVfpDefines.h"
#include "RimVfpTable.h"
#include "RimVfpTableData.h"
#include "Tools/RimPlotAxisTools.h"
@ -72,7 +73,7 @@ RimVfpPlot::RimVfpPlot()
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_PDM_InitFieldNoDefault( &m_vfpTable, "VfpTableData", "VFP Data Source" );
caf::AppEnum<RimVfpDefines::TableType> defaultTableType = RimVfpDefines::TableType::INJECTION;
CAF_PDM_InitField( &m_tableType, "TableType", defaultTableType, "Table Type" );
@ -140,8 +141,6 @@ RimVfpPlot::RimVfpPlot()
setAsPlotMdiWindow();
setDeletable( true );
m_vfpTables = std::make_unique<RigVfpTables>();
}
//--------------------------------------------------------------------------------------------------
@ -156,9 +155,9 @@ RimVfpPlot::~RimVfpPlot()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::setDataSource( RimVfpTableData* vfpTableData )
void RimVfpPlot::setDataSource( RimVfpTable* vfpTableData )
{
m_vfpTableData = vfpTableData;
m_vfpTable = vfpTableData;
}
//--------------------------------------------------------------------------------------------------
@ -176,7 +175,7 @@ void RimVfpPlot::initializeObject()
{
if ( !vfpTables() ) return;
auto tableNumber = m_tableNumber();
auto tableNumber = m_vfpTable->tableNumber();
// Always use the available table number if only one table is available
auto prodTableNumbers = vfpTables()->productionTableNumbers();
@ -284,9 +283,9 @@ QString RimVfpPlot::asciiDataForPlotExport() const
QString wellName;
if ( m_vfpTableData )
if ( m_vfpTable )
{
wellName = m_vfpTableData->name();
wellName = m_vfpTable->name();
}
else
{
@ -423,10 +422,10 @@ RiuPlotWidget* RimVfpPlot::doCreatePlotViewWidget( QWidget* mainWindowParent )
auto wheelZoomer = new RiuQwtPlotWheelZoomer( qwtPlot );
// Use lambda functions to connect signals to functions instead of slots
connect( wheelZoomer, &RiuQwtPlotWheelZoomer::zoomUpdated, [=]() { onPlotZoomed(); } );
connect( plotZoomer, &RiuQwtPlotZoomer::zoomed, [=]() { onPlotZoomed(); } );
connect( panner, &QwtPlotPanner::panned, [=]() { onPlotZoomed(); } );
connect( qwtPlotWidget, &RiuQwtPlotWidget::plotZoomed, [=]() { onPlotZoomed(); } );
connect( wheelZoomer, &RiuQwtPlotWheelZoomer::zoomUpdated, [=, this]() { onPlotZoomed(); } );
connect( plotZoomer, &RiuQwtPlotZoomer::zoomed, [=, this]() { onPlotZoomed(); } );
connect( panner, &QwtPlotPanner::panned, [=, this]() { onPlotZoomed(); } );
connect( qwtPlotWidget, &RiuQwtPlotWidget::plotZoomed, [=, this]() { onPlotZoomed(); } );
// Remove event filter to disable unwanted highlighting on left click in plot.
qwtPlotWidget->removeEventFilter();
@ -479,7 +478,7 @@ void RimVfpPlot::onLoadDataAndUpdate()
if ( vfpTables() )
{
wellName = m_vfpTableData->baseFileName();
wellName = vfpTableData()->baseFileName();
auto vfpPlotData = vfpTables()->populatePlotData( m_tableNumber(),
m_primaryVariable(),
@ -663,20 +662,25 @@ void RimVfpPlot::initializeFromInitData( const VfpTableInitialData& table )
m_flowingWaterFraction = table.waterFraction;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpTableData* RimVfpPlot::vfpTableData() const
{
if ( m_vfpTable ) return m_vfpTable->dataSource();
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const RigVfpTables* RimVfpPlot::vfpTables() const
{
if ( m_vfpTableData )
if ( vfpTableData() )
{
m_vfpTableData->ensureDataIsImported();
return m_vfpTableData->vfpTables();
}
if ( m_vfpTables )
{
return m_vfpTables.get();
vfpTableData()->ensureDataIsImported();
return vfpTableData()->vfpTables();
}
return nullptr;
@ -739,7 +743,7 @@ QString RimVfpPlot::getDisplayUnit( RimVfpDefines::ProductionVariableType variab
//--------------------------------------------------------------------------------------------------
void RimVfpPlot::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
uiOrdering.add( &m_vfpTableData );
uiOrdering.add( &m_vfpTable );
uiOrdering.add( &m_tableType );
uiOrdering.add( &m_tableNumber );
@ -813,7 +817,7 @@ QList<caf::PdmOptionItemInfo> RimVfpPlot::calculateValueOptions( const caf::PdmF
calculateTableValueOptions( RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO, options );
}
else if ( fieldNeedingOptions == &m_vfpTableData )
else if ( fieldNeedingOptions == &m_vfpTable )
{
RimVfpDataCollection* vfpDataCollection = RimVfpDataCollection::instance();
for ( auto table : vfpDataCollection->vfpTableData() )
@ -850,6 +854,11 @@ void RimVfpPlot::fieldChangedByUi( const caf::PdmFieldHandle* changedField, cons
{
RimPlot::fieldChangedByUi( changedField, oldValue, newValue );
if ( changedField == &m_vfpTable )
{
initializeObject();
}
loadDataAndUpdate();
updateLayout();
}

View File

@ -30,6 +30,7 @@ class RiuPlotWidget;
class VfpPlotData;
class RimPlotAxisProperties;
class RigVfpTables;
class RimVfpTable;
class RimVfpTableData;
struct VfpTableSelection;
@ -52,7 +53,7 @@ public:
RimVfpPlot();
~RimVfpPlot() override;
void setDataSource( RimVfpTableData* vfpTableData );
void setDataSource( RimVfpTable* vfpTableData );
void setTableNumber( int tableNumber );
void initializeObject();
@ -94,8 +95,10 @@ private:
void initAfterRead() override;
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
VfpTableSelection tableSelection() const;
void initializeFromInitData( const VfpTableInitialData& table );
VfpTableSelection tableSelection() const;
void initializeFromInitData( const VfpTableInitialData& table );
RimVfpTableData* vfpTableData() const;
const RigVfpTables* vfpTables() const;
RiuPlotWidget* doCreatePlotViewWidget( QWidget* mainWindowParent ) override;
@ -132,7 +135,7 @@ private:
private:
caf::PdmField<QString> m_plotTitle;
caf::PdmPtrField<RimVfpTableData*> m_vfpTableData;
caf::PdmPtrField<RimVfpTable*> m_vfpTable;
caf::PdmField<int> m_tableNumber;
caf::PdmField<double> m_referenceDepth;
caf::PdmField<caf::AppEnum<RimVfpDefines::FlowingPhaseType>> m_flowingPhase;
@ -157,8 +160,7 @@ private:
QPointer<RiuPlotWidget> m_plotWidget;
std::unique_ptr<RigVfpTables> m_vfpTables;
caf::PdmField<caf::FilePath> m_filePath_OBSOLETE;
caf::PdmField<caf::FilePath> m_filePath_OBSOLETE;
bool m_dataIsImportedExternally;
};

View File

@ -18,8 +18,8 @@
#include "RimVfpPlotCollection.h"
#include "RimVfpDeck.h"
#include "RimVfpTableData.h"
#include "RimCustomVfpPlot.h"
#include "RimVfpTable.h"
#include "cafCmdFeatureMenuBuilder.h"
@ -33,51 +33,48 @@ RimVfpPlotCollection::RimVfpPlotCollection()
CAF_PDM_InitObject( "VFP Plots", ":/VfpPlotCollection.svg" );
CAF_PDM_InitFieldNoDefault( &m_vfpPlots, "VfpPlots", "Vertical Flow Performance Plots" );
CAF_PDM_InitFieldNoDefault( &m_vfpDecks, "VfpDecks", "Vertical Flow Performance Decks" );
CAF_PDM_InitFieldNoDefault( &m_customVfpPlots, "CustomVfpPlots", "Vertical Flow Performance Plots" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpPlot* RimVfpPlotCollection::createAndAppendPlots( RimVfpTableData* tableData )
RimVfpPlot* RimVfpPlotCollection::createAndAppendPlots( RimVfpTable* 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 vfpPlot = new RimVfpPlot();
vfpPlot->setDataSource( tableData );
vfpPlot->initializeObject();
auto plots = deck->plots();
if ( !plots.empty() )
{
firstPlot = plots.front();
}
}
else
{
auto vfpPlot = new RimVfpPlot();
vfpPlot->setDataSource( tableData );
vfpPlot->initializeObject();
addPlot( vfpPlot );
vfpPlot->loadDataAndUpdate();
addPlot( vfpPlot );
vfpPlot->loadDataAndUpdate();
firstPlot = vfpPlot;
}
firstPlot = vfpPlot;
return firstPlot;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimCustomVfpPlot* RimVfpPlotCollection::createAndAppendPlots( RimVfpTable* mainDataSource, std::vector<RimVfpTable*> tableData )
{
auto vfpPlot = new RimCustomVfpPlot();
vfpPlot->selectDataSource( mainDataSource, tableData );
vfpPlot->initializeObject();
m_customVfpPlots.push_back( vfpPlot );
vfpPlot->loadDataAndUpdate();
return vfpPlot;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -135,21 +132,13 @@ void RimVfpPlotCollection::removePlot( RimVfpPlot* vfpPlot )
updateAllRequiredEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlotCollection::addDeck( RimVfpDeck* deck )
{
m_vfpDecks.push_back( deck );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpPlotCollection::deleteAllPlots()
{
m_vfpPlots.deleteChildren();
m_vfpDecks.deleteChildren();
m_customVfpPlots.deleteChildren();
}
//--------------------------------------------------------------------------------------------------
@ -185,9 +174,9 @@ void RimVfpPlotCollection::loadDataAndUpdateAllPlots()
plot->loadDataAndUpdate();
}
for ( auto deck : m_vfpDecks.childrenByType() )
for ( auto customPlot : m_customVfpPlots.childrenByType() )
{
deck->loadDataAndUpdate();
customPlot->loadDataAndUpdate();
}
}

View File

@ -23,7 +23,7 @@
#include "cafPdmChildArrayField.h"
#include "cafPdmObject.h"
class RimVfpDeck;
class RimCustomVfpPlot;
//==================================================================================================
///
@ -36,8 +36,9 @@ class RimVfpPlotCollection : public caf::PdmObject, public RimTypedPlotCollectio
public:
RimVfpPlotCollection();
RimVfpPlot* createAndAppendPlots( RimVfpTableData* tableData );
RimVfpPlot* plotForTableNumber( int tableNumber ) const;
RimVfpPlot* createAndAppendPlots( RimVfpTable* tableData );
RimVfpPlot* plotForTableNumber( int tableNumber ) const;
RimCustomVfpPlot* createAndAppendPlots( RimVfpTable* mainDataSource, std::vector<RimVfpTable*> tableData );
void addPlot( RimVfpPlot* newPlot ) override;
std::vector<RimVfpPlot*> plots() const override;
@ -55,9 +56,7 @@ private:
void appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const override;
void addDeck( RimVfpDeck* deck );
private:
caf::PdmChildArrayField<RimVfpPlot*> m_vfpPlots;
caf::PdmChildArrayField<RimVfpDeck*> m_vfpDecks;
caf::PdmChildArrayField<RimVfpPlot*> m_vfpPlots;
caf::PdmChildArrayField<RimCustomVfpPlot*> m_customVfpPlots;
};

View File

@ -0,0 +1,146 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 "RimVfpTable.h"
#include "cafCmdFeatureMenuBuilder.h"
CAF_PDM_SOURCE_INIT( RimVfpTable, "RimVfpTable" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpTable::RimVfpTable()
{
CAF_PDM_InitObject( "VFP Table", ":/VfpPlot.svg" );
CAF_PDM_InitFieldNoDefault( &m_dataSource, "DataSource", "Data Source" );
CAF_PDM_InitFieldNoDefault( &m_tableNumber, "TableNumber", "Table Number" );
CAF_PDM_InitFieldNoDefault( &m_tableType, "TableType", "Table Type" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpTable::setDataSource( RimVfpTableData* dataSource )
{
m_dataSource = dataSource;
updateObjectName();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpTable::setTableNumber( int tableNumber )
{
m_tableNumber = tableNumber;
updateObjectName();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpTable::setTableType( RimVfpDefines::TableType tableType )
{
m_tableType = tableType;
updateObjectName();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpTable::ensureDataIsImported()
{
if ( m_dataSource )
{
m_dataSource->ensureDataIsImported();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpTableData* RimVfpTable::dataSource() const
{
return m_dataSource;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RimVfpTable::tableNumber() const
{
return m_tableNumber;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimVfpDefines::TableType RimVfpTable::tableType() const
{
return m_tableType();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpTable::updateObjectName()
{
if ( m_dataSource )
{
QString name;
if ( m_tableNumber >= 0 )
{
if ( !name.isEmpty() ) name += " - ";
name += QString( "Table %1" ).arg( m_tableNumber );
}
if ( m_tableType() == RimVfpDefines::TableType::INJECTION )
{
if ( !name.isEmpty() ) name += " - ";
name += QString( "INJ" );
}
else
{
if ( !name.isEmpty() ) name += " - ";
name += QString( "PROD" );
}
if ( !name.isEmpty() ) name += " - ";
name += m_dataSource->name();
setName( name );
}
else
{
setName( "VFP Table" );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimVfpTable::appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const
{
menuBuilder << "RicNewVfpPlotFeature";
menuBuilder << "RicNewCustomVfpPlotFeature";
}

View File

@ -20,34 +20,39 @@
#include "RimNamedObject.h"
#include "cafFilePath.h"
#include "RimVfpDefines.h"
#include "RimVfpTableData.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.
///
//--------------------------------------------------------------------------------------------------
class RimVfpDeck : public RimNamedObject
class RimVfpTable : public RimNamedObject
{
CAF_PDM_HEADER_INIT;
public:
RimVfpDeck();
RimVfpTable();
void setDataSource( RimVfpTableData* tableData );
void loadDataAndUpdate();
RimVfpTableData* dataSource() const;
int tableNumber() const;
RimVfpDefines::TableType tableType() const;
std::vector<RimVfpPlot*> plots() const;
void setDataSource( RimVfpTableData* dataSource );
void setTableNumber( int tableNumber );
void setTableType( RimVfpDefines::TableType tableType );
void ensureDataIsImported();
private:
void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "" ) override;
void updateObjectName();
QList<caf::PdmOptionItemInfo> calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override;
void updateObjectName();
void appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const override;
private:
caf::PdmPtrField<RimVfpTableData*> m_vfpTableData;
caf::PdmChildField<RimVfpPlotCollection*> m_vfpPlotCollection;
caf::PdmPtrField<RimVfpTableData*> m_dataSource;
caf::PdmField<int> m_tableNumber;
caf::PdmField<caf::AppEnum<RimVfpDefines::TableType>> m_tableType;
};

View File

@ -22,6 +22,8 @@
#include "RigVfpTables.h"
#include "RimVfpTable.h"
#include "cafCmdFeatureMenuBuilder.h"
#include <QFileInfo>
@ -36,6 +38,8 @@ RimVfpTableData::RimVfpTableData()
CAF_PDM_InitObject( "VFP Plot", ":/VfpPlot.svg" );
CAF_PDM_InitFieldNoDefault( &m_filePath, "FilePath", "File Path" );
CAF_PDM_InitFieldNoDefault( &m_tables, "Tables", "Tables" );
m_tables.xmlCapability()->disableIO();
setDeletable( true );
}
@ -66,20 +70,42 @@ void RimVfpTableData::ensureDataIsImported()
updateObjectName();
m_tables.deleteChildren();
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 );
auto table = new RimVfpTable;
table->setDataSource( this );
table->setTableNumber( prod.getTableNum() );
table->setTableType( RimVfpDefines::TableType::PRODUCTION );
m_tables.push_back( table );
}
for ( const auto& inj : vfpInjTables )
{
m_vfpTables->addInjectionTable( inj );
auto table = new RimVfpTable;
table->setDataSource( this );
table->setTableNumber( inj.getTableNum() );
table->setTableType( RimVfpDefines::TableType::INJECTION );
m_tables.push_back( table );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimVfpTable*> RimVfpTableData::tableDataSources() const
{
return m_tables.childrenByType();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -123,4 +149,5 @@ void RimVfpTableData::updateObjectName()
void RimVfpTableData::appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const
{
menuBuilder << "RicNewVfpPlotFeature";
menuBuilder << "RicNewCustomVfpPlotFeature";
}

View File

@ -25,6 +25,7 @@
#include <memory>
class RigVfpTables;
class RimVfpTable;
//--------------------------------------------------------------------------------------------------
///
@ -40,6 +41,8 @@ public:
QString baseFileName();
void ensureDataIsImported();
std::vector<RimVfpTable*> tableDataSources() const;
size_t tableCount() const;
const RigVfpTables* vfpTables() const;
@ -49,7 +52,8 @@ private:
void appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const override;
private:
caf::PdmField<caf::FilePath> m_filePath;
caf::PdmField<caf::FilePath> m_filePath;
caf::PdmChildArrayField<RimVfpTable*> m_tables;
std::unique_ptr<RigVfpTables> m_vfpTables;
};

View File

@ -173,6 +173,130 @@ VfpPlotData RigVfpTables::populatePlotData( int
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
VfpPlotData RigVfpTables::populatePlotData( int tableIndex,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase,
const VfpValueSelection& valueSelection ) const
{
auto prodTable = productionTable( tableIndex );
if ( prodTable.has_value() )
{
return populatePlotData( *prodTable, primaryVariable, familyVariable, interpolatedVariable, flowingPhase, valueSelection );
}
auto injContainer = injectionTable( tableIndex );
if ( injContainer.has_value() )
{
return populatePlotData( *injContainer, interpolatedVariable, flowingPhase );
}
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
VfpPlotData RigVfpTables::populatePlotData( const Opm::VFPProdTable& table,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase,
const VfpValueSelection& valueSelection )
{
VfpPlotData plotData;
QString xAxisTitle = axisTitle( primaryVariable, flowingPhase );
plotData.setXAxisTitle( xAxisTitle );
QString yAxisTitle = QString( "%1 %2" ).arg( caf::AppEnum<RimVfpDefines::InterpolatedVariableType>::uiText( interpolatedVariable ),
getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType::THP ) );
plotData.setYAxisTitle( yAxisTitle );
std::vector<double> familyFilterValues = valueSelection.familyValues;
size_t numFamilyValues = getProductionTableData( table, familyVariable ).size();
for ( size_t familyIdx = 0; familyIdx < numFamilyValues; familyIdx++ )
{
std::vector<double> primaryAxisValues = getProductionTableData( table, primaryVariable );
std::vector<double> familyVariableValues = getProductionTableData( table, familyVariable );
std::vector<double> thpValues = getProductionTableData( table, RimVfpDefines::ProductionVariableType::THP );
// Skip if the family value is not in the filter
auto currentFamilyValue = familyVariableValues[familyIdx];
auto it = std::find( familyFilterValues.begin(), familyFilterValues.end(), currentFamilyValue );
if ( it == familyFilterValues.end() ) continue;
size_t numValues = primaryAxisValues.size();
std::vector<double> yVals( numValues, 0.0 );
for ( size_t y = 0; y < numValues; y++ )
{
auto currentPrimaryValue = primaryAxisValues[y];
size_t wfr_idx = getVariableIndexForValue( table,
RimVfpDefines::ProductionVariableType::WATER_CUT,
primaryVariable,
currentPrimaryValue,
familyVariable,
currentFamilyValue,
valueSelection );
size_t gfr_idx = getVariableIndexForValue( table,
RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO,
primaryVariable,
currentPrimaryValue,
familyVariable,
currentFamilyValue,
valueSelection );
size_t alq_idx = getVariableIndexForValue( table,
RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY,
primaryVariable,
currentPrimaryValue,
familyVariable,
currentFamilyValue,
valueSelection );
size_t flo_idx = getVariableIndexForValue( table,
RimVfpDefines::ProductionVariableType::FLOW_RATE,
primaryVariable,
currentPrimaryValue,
familyVariable,
currentFamilyValue,
valueSelection );
size_t thp_idx = getVariableIndexForValue( table,
RimVfpDefines::ProductionVariableType::THP,
primaryVariable,
currentPrimaryValue,
familyVariable,
currentFamilyValue,
valueSelection );
yVals[y] = table( thp_idx, wfr_idx, gfr_idx, alq_idx, flo_idx );
if ( interpolatedVariable == RimVfpDefines::InterpolatedVariableType::BHP_THP_DIFF )
{
yVals[y] -= thpValues[thp_idx];
}
}
double familyValue = convertToDisplayUnit( currentFamilyValue, familyVariable );
QString familyUnit = getDisplayUnit( familyVariable );
QString familyTitle = QString( "%1: %2 %3" )
.arg( caf::AppEnum<RimVfpDefines::ProductionVariableType>::uiText( familyVariable ) )
.arg( familyValue )
.arg( familyUnit );
convertToDisplayUnit( yVals, RimVfpDefines::ProductionVariableType::THP );
convertToDisplayUnit( primaryAxisValues, primaryVariable );
plotData.appendCurve( familyTitle, primaryAxisValues, yVals );
}
return plotData;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -201,6 +325,89 @@ QString RigVfpTables::asciiDataForTable( int
return textForPlotData( plotData );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<int> RigVfpTables::findClosestIndices( const std::vector<double>& sourceValues, const std::vector<double>& valuesToMatch )
{
std::vector<int> result( sourceValues.size(), -1 );
// Returns the indices of the closest values in valuesToMatch for each value in sourceValues.
for ( size_t i = 0; i < sourceValues.size(); ++i )
{
double minDistance = std::numeric_limits<double>::max();
int closestIndex = -1;
for ( size_t j = 0; j < valuesToMatch.size(); ++j )
{
double distance = std::abs( sourceValues[i] - valuesToMatch[j] );
if ( distance < minDistance )
{
minDistance = distance;
closestIndex = static_cast<int>( j );
}
}
if ( closestIndex < static_cast<int>( valuesToMatch.size() ) )
{
result[i] = closestIndex;
}
}
return result;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<int> RigVfpTables::uniqueClosestIndices( const std::vector<double>& sourceValues, const std::vector<double>& valuesToMatch )
{
// Find the closest value in valuesForMatch for each value in sourceValues
std::vector<double> distances( sourceValues.size(), std::numeric_limits<double>::max() );
auto closestIndices = findClosestIndices( sourceValues, valuesToMatch );
for ( size_t i = 0; i < sourceValues.size(); i++ )
{
if ( closestIndices[i] >= 0 )
{
distances[i] = std::abs( sourceValues[i] - valuesToMatch[closestIndices[i]] );
}
}
while ( std::any_of( distances.begin(), distances.end(), []( double val ) { return val != std::numeric_limits<double>::max(); } ) )
{
// find the index of the smallest value in minDistance
auto minDistanceIt = std::min_element( distances.begin(), distances.end() );
if ( minDistanceIt == distances.end() )
{
break;
}
auto minDistanceIndex = std::distance( distances.begin(), minDistanceIt );
auto matchingIndex = closestIndices[minDistanceIndex];
if ( matchingIndex > -1 )
{
// Remove all references to the matching index
for ( size_t i = 0; i < sourceValues.size(); i++ )
{
if ( i == static_cast<size_t>( minDistanceIndex ) )
{
distances[i] = std::numeric_limits<double>::max();
}
else if ( closestIndices[i] == matchingIndex )
{
distances[i] = std::numeric_limits<double>::max();
closestIndices[i] = -1;
}
}
}
}
return closestIndices;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -385,6 +592,90 @@ size_t RigVfpTables::getVariableIndex( const Opm::VFPProdTable& tab
return getProductionTableData( table, targetVariable ).size() - 1;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RigVfpTables::getVariableIndexForValue( const Opm::VFPProdTable& table,
RimVfpDefines::ProductionVariableType targetVariable,
RimVfpDefines::ProductionVariableType primaryVariable,
double primaryValue,
RimVfpDefines::ProductionVariableType familyVariable,
double familyValue,
const VfpValueSelection& valueSelection )
{
auto findClosestIndex = []( const std::vector<double>& values, const double value )
{
auto it = std::lower_bound( values.begin(), values.end(), value );
if ( it == values.begin() )
{
return (size_t)0;
}
if ( it == values.end() )
{
return values.size() - 1;
}
if ( *it == value )
{
return (size_t)std::distance( values.begin(), it );
}
auto prev = it - 1;
if ( std::abs( *prev - value ) < std::abs( *it - value ) )
{
return (size_t)std::distance( values.begin(), prev );
}
return (size_t)std::distance( values.begin(), it );
};
if ( targetVariable == primaryVariable )
{
const auto values = getProductionTableData( table, targetVariable );
return findClosestIndex( values, primaryValue );
}
if ( targetVariable == familyVariable )
{
const auto values = getProductionTableData( table, targetVariable );
return findClosestIndex( values, familyValue );
}
auto findClosestIndexForVariable =
[&]( RimVfpDefines::ProductionVariableType targetVariable, const double selectedValue, const Opm::VFPProdTable& table )
{
const auto values = getProductionTableData( table, targetVariable );
return findClosestIndex( values, selectedValue );
};
switch ( targetVariable )
{
case RimVfpDefines::ProductionVariableType::WATER_CUT:
{
return findClosestIndexForVariable( targetVariable, valueSelection.waterCutValue, table );
}
case RimVfpDefines::ProductionVariableType::GAS_LIQUID_RATIO:
{
return findClosestIndexForVariable( targetVariable, valueSelection.gasLiquidRatioValue, table );
}
case RimVfpDefines::ProductionVariableType::ARTIFICIAL_LIFT_QUANTITY:
{
return findClosestIndexForVariable( targetVariable, valueSelection.articifialLiftQuantityValue, table );
}
case RimVfpDefines::ProductionVariableType::FLOW_RATE:
{
return findClosestIndexForVariable( targetVariable, valueSelection.flowRateValue, table );
}
case RimVfpDefines::ProductionVariableType::THP:
{
return findClosestIndexForVariable( targetVariable, valueSelection.thpValue, table );
}
default:
break;
}
return 0;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -73,6 +73,17 @@ struct VfpTableSelection
int gasLiquidRatioIdx;
};
struct VfpValueSelection
{
double flowRateValue;
double thpValue;
double articifialLiftQuantityValue;
double waterCutValue;
double gasLiquidRatioValue;
std::vector<double> familyValues;
};
struct VfpTableInitialData
{
bool isProductionTable;
@ -106,6 +117,13 @@ public:
RimVfpDefines::FlowingPhaseType flowingPhase,
const VfpTableSelection& tableSelection ) const;
VfpPlotData populatePlotData( int tableIndex,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase,
const VfpValueSelection& valueSelection ) const;
QString asciiDataForTable( int tableNumber,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable,
@ -113,6 +131,10 @@ public:
RimVfpDefines::FlowingPhaseType flowingPhase,
const VfpTableSelection& tableSelection ) const;
// Returns the indices of the closest values in valuesToMatch for each value in sourceValues. Returned index value -1 indicates no
// match. A index value is only returned once.
static std::vector<int> uniqueClosestIndices( const std::vector<double>& sourceValues, const std::vector<double>& valuesToMatch );
private:
static VfpPlotData populatePlotData( const Opm::VFPInjTable& table,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
@ -125,6 +147,13 @@ private:
RimVfpDefines::FlowingPhaseType flowingPhase,
const VfpTableSelection& tableSelection );
static VfpPlotData populatePlotData( const Opm::VFPProdTable& table,
RimVfpDefines::ProductionVariableType primaryVariable,
RimVfpDefines::ProductionVariableType familyVariable,
RimVfpDefines::InterpolatedVariableType interpolatedVariable,
RimVfpDefines::FlowingPhaseType flowingPhase,
const VfpValueSelection& valueSelection );
static QString axisTitle( RimVfpDefines::ProductionVariableType variableType, RimVfpDefines::FlowingPhaseType flowingPhase );
static QString getDisplayUnit( RimVfpDefines::ProductionVariableType variableType );
static QString getDisplayUnitWithBracket( RimVfpDefines::ProductionVariableType variableType );
@ -143,6 +172,14 @@ private:
size_t familyValue,
const VfpTableSelection& tableSelection );
static size_t getVariableIndexForValue( const Opm::VFPProdTable& table,
RimVfpDefines::ProductionVariableType targetVariable,
RimVfpDefines::ProductionVariableType primaryVariable,
double primaryValue,
RimVfpDefines::ProductionVariableType familyVariable,
double familyValue,
const VfpValueSelection& valueSelection );
std::optional<Opm::VFPInjTable> injectionTable( int tableNumber ) const;
std::optional<Opm::VFPProdTable> productionTable( int tableNumber ) const;
@ -151,6 +188,9 @@ private:
static RimVfpDefines::FlowingWaterFractionType getFlowingWaterFractionType( const Opm::VFPProdTable& table );
static RimVfpDefines::FlowingGasFractionType getFlowingGasFractionType( const Opm::VFPProdTable& table );
// Returns the indices of the closest values in valuesToMatch for each value in sourceValues. Returned index value -1 indicates no match.
static std::vector<int> findClosestIndices( const std::vector<double>& sourceValues, const std::vector<double>& valuesToMatch );
private:
std::vector<Opm::VFPInjTable> m_injectionTables;
std::vector<Opm::VFPProdTable> m_productionTables;

View File

@ -104,6 +104,7 @@ set(SOURCE_UNITTEST_FILES
${CMAKE_CURRENT_LIST_DIR}/RifPolygonReader-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RifParquetReader-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RifOsduWellPathReader-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RigVfpTables-Test.cpp
)
if(RESINSIGHT_ENABLE_GRPC)

View File

@ -0,0 +1,83 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 "gtest/gtest.h"
#include "RigVfpTables.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RigVfpTables, MatchingValues )
{
std::vector<double> sourceValues = { 1.0, 2.0, 3.0, 4.0, 5.0 };
std::vector<double> valuesForMatch = { 1.0, 2.0, 3.0, 4.0, 5.0 };
std::vector<int> closestIndices = RigVfpTables::uniqueClosestIndices( sourceValues, valuesForMatch );
for ( int i = 0; i < sourceValues.size(); i++ )
{
EXPECT_EQ( i, closestIndices[i] );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RigVfpTables, MoreDestinationValues )
{
std::vector<double> sourceValues = { 1.0, 2.0, 3.0, 4.0, 5.0 };
std::vector<double> valuesForMatch = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 };
std::vector<int> closestIndices = RigVfpTables::uniqueClosestIndices( sourceValues, valuesForMatch );
for ( int i = 0; i < sourceValues.size(); i++ )
{
EXPECT_EQ( i, closestIndices[i] );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RigVfpTables, MatchInBetweenValues )
{
std::vector<double> sourceValues = { 1.0, 2.0, 3.0, 4.0, 5.0 };
std::vector<double> valuesForMatch = { 1.0, 1.5, 2.0, 3.0, 4.0, 5.0, 6.0 };
std::vector<int> closestIndices = RigVfpTables::uniqueClosestIndices( sourceValues, valuesForMatch );
EXPECT_EQ( 5, (int)closestIndices.size() );
EXPECT_EQ( 0, closestIndices[0] );
EXPECT_EQ( 2, closestIndices[1] );
EXPECT_EQ( 3, closestIndices[2] );
EXPECT_EQ( 4, closestIndices[3] );
EXPECT_EQ( 5, closestIndices[4] );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RigVfpTables, SingleValue )
{
std::vector<double> sourceValues = { 1.0, 2.0, 3.0 };
std::vector<double> valuesForMatch = { 2.1 };
std::vector<int> closestIndices = RigVfpTables::uniqueClosestIndices( sourceValues, valuesForMatch );
EXPECT_EQ( 3, (int)closestIndices.size() );
EXPECT_EQ( -1, closestIndices[0] );
EXPECT_EQ( 0, closestIndices[1] );
EXPECT_EQ( -1, closestIndices[2] );
}

View File

@ -39,10 +39,7 @@ class PdmPtrField<DataType*> : public PdmValueField
public:
typedef PdmPointer<DataType> FieldDataType;
PdmPtrField()
: m_isResolved( false )
{
}
PdmPtrField() {}
explicit PdmPtrField( const DataTypePtr& fieldValue );
~PdmPtrField() override;
@ -81,7 +78,6 @@ private:
// Resolving
QString m_referenceString;
bool m_isResolved;
};
} // End of namespace caf

View File

@ -29,7 +29,6 @@ void caf::PdmPtrField<DataType*>::setFromQVariant( const QVariant& variant )
template <typename DataType>
caf::PdmPtrField<DataType*>::PdmPtrField( const DataTypePtr& fieldValue )
{
m_isResolved = true;
m_fieldValue = fieldValue;
if ( m_fieldValue != NULL ) m_fieldValue->addReferencingPtrField( this );
}

View File

@ -54,7 +54,6 @@ public:
{
m_field = field;
m_dataTypeName = DataType::classKeywordStatic();
m_isResolved = false;
m_referenceString = "";
}
@ -70,7 +69,6 @@ private:
// Resolving
QString m_referenceString;
bool m_isResolved;
};
template <typename DataType>
@ -87,7 +85,6 @@ public:
{
m_field = field;
m_dataTypeName = DataType::classKeywordStatic();
m_isResolved = false;
m_referenceString = "";
}
@ -103,7 +100,6 @@ private:
// Resolving
QString m_referenceString;
bool m_isResolved;
};
template <typename DataType>

View File

@ -90,7 +90,6 @@ void caf::PdmFieldXmlCap<caf::PdmPtrField<DataType*>>::readFieldData( QXmlStream
//
// and then we need a traversal of the object hierarchy to resolve all references before initAfterRead.
m_isResolved = false;
m_referenceString = dataString;
m_field->setRawPtr( NULL );
}
@ -117,12 +116,11 @@ void caf::PdmFieldXmlCap<caf::PdmPtrField<DataType*>>::writeFieldData( QXmlStrea
template <typename DataType>
bool caf::PdmFieldXmlCap<PdmPtrField<DataType*>>::resolveReferences()
{
if ( m_isResolved ) return true;
if ( m_field->m_fieldValue.rawPtr() != nullptr ) return true;
if ( m_referenceString.isEmpty() ) return true;
PdmObjectHandle* objHandle = PdmReferenceHelper::objectFromFieldReference( this->fieldHandle(), m_referenceString );
m_field->setRawPtr( objHandle );
m_isResolved = true;
return objHandle != nullptr;
}
@ -163,7 +161,6 @@ void caf::PdmFieldXmlCap<caf::PdmPtrArrayField<DataType*>>::readFieldData( QXmlS
// It must be done when we know that the complete hierarchy is read and created,
// and then we need a traversal of the object hierarchy to resolve all references before initAfterRead.
m_isResolved = false;
m_referenceString = dataString;
m_field->clearWithoutDelete();
}
@ -193,7 +190,6 @@ void caf::PdmFieldXmlCap<caf::PdmPtrArrayField<DataType*>>::writeFieldData( QXml
template <typename DataType>
bool caf::PdmFieldXmlCap<PdmPtrArrayField<DataType*>>::resolveReferences()
{
if ( m_isResolved ) return true;
if ( m_referenceString.isEmpty() ) return true;
m_field->clearWithoutDelete();
@ -211,8 +207,6 @@ bool caf::PdmFieldXmlCap<PdmPtrArrayField<DataType*>>::resolveReferences()
m_field->m_pointers.back().setRawPtr( objHandle );
}
m_isResolved = true;
return foundValidObjectFromString;
}

View File

@ -197,7 +197,11 @@ TEST( AdvancedObjectTest, FieldWrite )
a->readObjectFromXmlString( serializedString, caf::PdmDefaultObjectFactory::instance() );
a->xmlCapability()->resolveReferencesRecursively();
ASSERT_TRUE( a->m_pointerToItem() == container->m_items[1] );
// Set pointer to null. The reference string is still valid, and the resolving will restore the pointer.
a->m_pointerToItem = nullptr;
a->xmlCapability()->resolveReferencesRecursively();
ASSERT_TRUE( a->m_pointerToItem() == container->m_items[1] );
}
}

View File

@ -551,11 +551,18 @@ void PdmUiTreeSelectionEditor::slotToggleAll()
{
if ( m_toggleAllCheckBox->isChecked() )
{
checkAllItems();
checkAllItemsMatchingFilter();
return;
}
unCheckAllItems();
if ( m_textFilterLineEdit->text().isEmpty() )
{
m_model->unselectAllItems();
}
else
{
unCheckAllItemsMatchingFilter();
}
// Apply integer filtering if the model contains only integers
if ( hasOnlyIntegers( m_model ) )
@ -788,7 +795,7 @@ void PdmUiTreeSelectionEditor::currentChanged( const QModelIndex& current )
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeSelectionEditor::checkAllItems()
void PdmUiTreeSelectionEditor::checkAllItemsMatchingFilter()
{
QModelIndexList indices = allVisibleSourceModelIndices();
@ -798,7 +805,7 @@ void PdmUiTreeSelectionEditor::checkAllItems()
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiTreeSelectionEditor::unCheckAllItems()
void PdmUiTreeSelectionEditor::unCheckAllItemsMatchingFilter()
{
QModelIndexList indices = allVisibleSourceModelIndices();

View File

@ -127,8 +127,8 @@ private:
void setCheckedStateOfSelected( bool checked );
void setCheckedStateForSubItemsOfSelected( bool checked );
void checkAllItems();
void unCheckAllItems();
void checkAllItemsMatchingFilter();
void unCheckAllItemsMatchingFilter();
void setCheckedStateForIntegerItemsMatchingFilter();
QModelIndexList allVisibleSourceModelIndices() const;

View File

@ -173,6 +173,14 @@ void caf::PdmUiTreeSelectionQModel::invertCheckedStateForItems( const QModelInde
PdmUiCommandSystemProxy::instance()->setUiValueToField( m_uiFieldHandle->uiField(), fieldValueSelection );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void caf::PdmUiTreeSelectionQModel::unselectAllItems()
{
PdmUiCommandSystemProxy::instance()->setUiValueToField( m_uiFieldHandle->uiField(), {} );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -63,6 +63,7 @@ public:
void setCheckedStateForItems( const QModelIndexList& indices, bool checked );
void invertCheckedStateForItems( const QModelIndexList& indices );
void unselectAllItems();
void enableSingleSelectionMode( bool enable );