From ab43e67f0f75c22b2c168362910b551faa6cea26 Mon Sep 17 00:00:00 2001 From: Kristian Bendiksen Date: Mon, 7 Sep 2026 14:45:27 +0200 Subject: [PATCH] #14345 Add Data Filters to grid ensembles Add a data filter collection to RimReservoirGridEnsemble, so filters can be defined once for the ensemble. The filters are bound to the main case of the ensemble for configuration. Expose filter creation commands from a Data Filters submenu on the ensemble node, and hide the collection node while empty, matching the case-level behavior. Grid calculation integration is intentionally left for the dependent calculation-filtering change. --- .../RicCellFilterFeatureTools.h | 12 ++++-- .../RicNewPolygonFilterFeature.cpp | 5 ++- .../RimReservoirGridEnsemble.cpp | 40 +++++++++++++++++++ .../RimReservoirGridEnsemble.h | 8 ++++ 4 files changed, 59 insertions(+), 6 deletions(-) diff --git a/ApplicationLibCode/Commands/CellFilterCommands/RicCellFilterFeatureTools.h b/ApplicationLibCode/Commands/CellFilterCommands/RicCellFilterFeatureTools.h index 963465c7e4..475b8f77f5 100644 --- a/ApplicationLibCode/Commands/CellFilterCommands/RicCellFilterFeatureTools.h +++ b/ApplicationLibCode/Commands/CellFilterCommands/RicCellFilterFeatureTools.h @@ -28,6 +28,7 @@ #include "RimEclipseCase.h" #include "RimFilterInViewCollection.h" #include "RimGridView.h" +#include "RimReservoirGridEnsemble.h" #include "Riu3DMainWindowTools.h" @@ -84,10 +85,10 @@ inline RimCellFilterCollection* resolveTargetCellFilterCollection() } //-------------------------------------------------------------------------------------------------- -/// Resolve the case-level RimDataFilterCollection to target from the current selection: either the -/// data-filter collection node itself, or a selected RimEclipseCase (whose "Data Filters" node is -/// hidden while empty, so the case node is right-clicked to create the first filter). Returns -/// nullptr if neither is selected. +/// Resolve the RimDataFilterCollection to target from the current selection: either the data-filter +/// collection node itself, or a selected RimEclipseCase or RimReservoirGridEnsemble (whose "Data +/// Filters" node is hidden while empty, so the owner node is right-clicked to create the first +/// filter). Returns nullptr if none is selected. //-------------------------------------------------------------------------------------------------- inline RimDataFilterCollection* selectedDataFilterCollection() { @@ -97,6 +98,9 @@ inline RimDataFilterCollection* selectedDataFilterCollection() auto cases = caf::selectedObjectsByTypeStrict(); if ( !cases.empty() && cases.front() ) return cases.front()->dataFilterCollection(); + auto ensembles = caf::selectedObjectsByTypeStrict(); + if ( !ensembles.empty() && ensembles.front() ) return ensembles.front()->dataFilterCollection(); + return nullptr; } diff --git a/ApplicationLibCode/Commands/CellFilterCommands/RicNewPolygonFilterFeature.cpp b/ApplicationLibCode/Commands/CellFilterCommands/RicNewPolygonFilterFeature.cpp index 9997c72c25..3896bf8f7f 100644 --- a/ApplicationLibCode/Commands/CellFilterCommands/RicNewPolygonFilterFeature.cpp +++ b/ApplicationLibCode/Commands/CellFilterCommands/RicNewPolygonFilterFeature.cpp @@ -104,8 +104,9 @@ void RicNewPolygonFilterFeature::onActionTriggered( bool isChecked ) return; } - // If a case-level Data Filter Collection is selected, add polygon filters there. - auto* dataCollection = caf::SelectionManager::instance()->selectedItemOfType(); + // If a case or ensemble level Data Filter Collection is selected (or its owner node), add + // polygon filters there. + auto* dataCollection = RicCellFilterFeatureTools::selectedDataFilterCollection(); if ( dataCollection ) { if ( polygons.empty() ) polygons.push_back( nullptr ); diff --git a/ApplicationLibCode/ProjectDataModel/RimReservoirGridEnsemble.cpp b/ApplicationLibCode/ProjectDataModel/RimReservoirGridEnsemble.cpp index 8ce3a7d72a..89d811bc1e 100644 --- a/ApplicationLibCode/ProjectDataModel/RimReservoirGridEnsemble.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimReservoirGridEnsemble.cpp @@ -18,6 +18,8 @@ #include "RimReservoirGridEnsemble.h" +#include "cafPdmUiTreeOrdering.h" + #include "RiaLogging.h" #include "RiaQStringFormatter.h" #include "RiaResultNames.h" @@ -37,6 +39,7 @@ #include "Formations/RimFormationNamesCollection.h" #include "Rim2dIntersectionViewCollection.h" #include "RimCaseCollection.h" +#include "RimDataFilterCollection.h" #include "RimEclipseCase.h" #include "RimEclipseCellColors.h" #include "RimEclipseResultCase.h" @@ -111,6 +114,9 @@ RimReservoirGridEnsemble::RimReservoirGridEnsemble() CAF_PDM_InitFieldNoDefault( &m_ensembleCase, "EnsembleCase", "Ensemble Grid" ); m_ensembleCase = nullptr; + CAF_PDM_InitScriptableFieldNoDefault( &m_dataFilterCollection, "DataFilterCollection", "Data Filters" ); + m_dataFilterCollection = new RimDataFilterCollection; + CAF_PDM_InitFieldNoDefault( &m_viewCollection, "ViewCollection", "Views" ); m_viewCollection = new RimEclipseViewCollection; m_viewCollection->setEclipseCaseProvider( [this]() { return this->cases(); } ); @@ -195,6 +201,7 @@ void RimReservoirGridEnsemble::addCase( RimEclipseCase* reservoir ) clearActiveCellUnions(); clearStatisticsResults(); updateMainGridAndActiveCellsForStatisticsCases(); + updateDataFilterCollectionCase(); } //-------------------------------------------------------------------------------------------------- @@ -214,6 +221,7 @@ void RimReservoirGridEnsemble::removeCase( RimEclipseCase* reservoir ) clearActiveCellUnions(); clearStatisticsResults(); updateMainGridAndActiveCellsForStatisticsCases(); + updateDataFilterCollectionCase(); } //-------------------------------------------------------------------------------------------------- @@ -648,6 +656,13 @@ void RimReservoirGridEnsemble::appendMenuItems( caf::CmdFeatureMenuBuilder& menu { menuBuilder << "RicNewStatisticsCaseFeature"; } + + // The "Data Filters" collection node is hidden while empty, so expose the filter creation + // commands on the ensemble node to allow creating the first filter. + menuBuilder << "Separator"; + menuBuilder.subMenuStart( "Data Filters", QIcon( ":/CellFilter.png" ) ); + m_dataFilterCollection->appendMenuItems( menuBuilder ); + menuBuilder.subMenuEnd(); } //-------------------------------------------------------------------------------------------------- @@ -659,6 +674,24 @@ RimFormationNames* RimReservoirGridEnsemble::activeFormationNames() const return m_activeFormationNames(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimDataFilterCollection* RimReservoirGridEnsemble::dataFilterCollection() const +{ + return m_dataFilterCollection(); +} + +//-------------------------------------------------------------------------------------------------- +/// The filters in the collection need a source case for configuration (result meta data, grid +/// geometry). Use the main case of the ensemble. Evaluation of the filters is done per case, see +/// RimCellFilterTools::computeReservoirCellVisibility. +//-------------------------------------------------------------------------------------------------- +void RimReservoirGridEnsemble::updateDataFilterCollectionCase() +{ + if ( m_dataFilterCollection() ) m_dataFilterCollection->setCase( mainCase() ); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -725,6 +758,12 @@ void RimReservoirGridEnsemble::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiT uiTreeOrdering.add( &m_caseCollection ); uiTreeOrdering.add( &m_statisticsCaseCollection ); + + if ( m_dataFilterCollection() && m_dataFilterCollection()->shouldBeVisibleInTree() ) + { + uiTreeOrdering.add( m_dataFilterCollection() ); + } + uiTreeOrdering.add( &m_viewCollection ); for ( auto eclipseCase : cases() ) @@ -793,6 +832,7 @@ void RimReservoirGridEnsemble::initAfterRead() m_viewCollection->setEclipseCaseProvider( [this]() { return this->cases(); } ); } + updateDataFilterCollectionCase(); updateStatisticsVisibility(); } diff --git a/ApplicationLibCode/ProjectDataModel/RimReservoirGridEnsemble.h b/ApplicationLibCode/ProjectDataModel/RimReservoirGridEnsemble.h index 59e95892e0..2250bfa397 100644 --- a/ApplicationLibCode/ProjectDataModel/RimReservoirGridEnsemble.h +++ b/ApplicationLibCode/ProjectDataModel/RimReservoirGridEnsemble.h @@ -35,6 +35,7 @@ class RigActiveCellInfo; class RigMainGrid; class RimCaseCollection; +class RimDataFilterCollection; class RimEclipseCase; class RimEclipseStatisticsCase; class RimEclipseView; @@ -98,6 +99,9 @@ public: // Formation names RimFormationNames* activeFormationNames() const override; + // Data filters + RimDataFilterCollection* dataFilterCollection() const; + // Statistics RimCaseCollection* statisticsCaseCollection() const override; RimEclipseStatisticsCase* createAndAppendStatisticsCase() override; @@ -144,6 +148,7 @@ private: void loadGridsInSharedMode(); void loadGridsInIndividualMode(); void updateGridModeToolTip(); + void updateDataFilterCollectionCase(); private: // File set reference @@ -160,6 +165,9 @@ private: caf::PdmChildField m_statisticsCaseCollection; caf::PdmChildField m_ensembleCase; + // Data filters + caf::PdmChildField m_dataFilterCollection; + // Grid mode caf::PdmField m_autoDetectGridType; caf::PdmField> m_gridMode;