diff --git a/ApplicationExeCode/Resources/GridAndSummaryEnsemble.svg b/ApplicationExeCode/Resources/GridAndSummaryEnsemble.svg new file mode 100644 index 0000000000..a515af80ea --- /dev/null +++ b/ApplicationExeCode/Resources/GridAndSummaryEnsemble.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/ApplicationExeCode/Resources/ResInsight.qrc b/ApplicationExeCode/Resources/ResInsight.qrc index aee7bb79d6..a639764a1c 100644 --- a/ApplicationExeCode/Resources/ResInsight.qrc +++ b/ApplicationExeCode/Resources/ResInsight.qrc @@ -142,6 +142,7 @@ SummaryCases16x16.png SummaryCurve16x16.png SummaryCurveFilter16x16.png + GridAndSummaryEnsemble.svg SummaryEnsemble.svg SummaryGroup16x16.png SummaryPlotLight16x16.png diff --git a/ApplicationLibCode/Commands/CMakeLists_files.cmake b/ApplicationLibCode/Commands/CMakeLists_files.cmake index dad7149947..3c8f3d4c58 100644 --- a/ApplicationLibCode/Commands/CMakeLists_files.cmake +++ b/ApplicationLibCode/Commands/CMakeLists_files.cmake @@ -101,6 +101,8 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RicCreateContourMapPolygonTools.h ${CMAKE_CURRENT_LIST_DIR}/RicPolygonFromImageDialog.h ${CMAKE_CURRENT_LIST_DIR}/RicCreateSummaryEnsembleFeature.h + ${CMAKE_CURRENT_LIST_DIR}/RicImportGridAndSummaryEnsembleDialog.h + ${CMAKE_CURRENT_LIST_DIR}/RicImportGridAndSummaryEnsembleFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicHistogramPlotTools.h ${CMAKE_CURRENT_LIST_DIR}/RicCreateGridStatisticsPlotFeature.h ) @@ -208,6 +210,8 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RicCreateContourMapPolygonTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RicPolygonFromImageDialog.cpp ${CMAKE_CURRENT_LIST_DIR}/RicCreateSummaryEnsembleFeature.cpp + ${CMAKE_CURRENT_LIST_DIR}/RicImportGridAndSummaryEnsembleDialog.cpp + ${CMAKE_CURRENT_LIST_DIR}/RicImportGridAndSummaryEnsembleFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicHistogramPlotTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RicCreateGridStatisticsPlotFeature.cpp ) diff --git a/ApplicationLibCode/Commands/RicImportEnsembleFeature.h b/ApplicationLibCode/Commands/RicImportEnsembleFeature.h index c723df58a2..e969930fd2 100644 --- a/ApplicationLibCode/Commands/RicImportEnsembleFeature.h +++ b/ApplicationLibCode/Commands/RicImportEnsembleFeature.h @@ -26,6 +26,7 @@ #include class RimSummaryCase; +class RimSummaryEnsemble; //================================================================================================== /// @@ -41,6 +42,12 @@ public: RiaDefines::EnsembleGroupingMode groupingMode, bool isEnsemble = false ); + static RimSummaryEnsemble* importSingleEnsembleFileSet( const QStringList& fileNames, + bool useEnsembleNameDialog, + RiaDefines::EnsembleGroupingMode groupingMode, + RiaDefines::FileType fileType, + const QString& defaultEnsembleName = QString() ); + private: void onActionTriggered( bool isChecked ) override; void setupActionLook( QAction* actionToSetup ) override; @@ -51,10 +58,4 @@ private: RiaDefines::EnsembleGroupingMode groupingMode, RiaDefines::FileType fileType, const QString& defaultEnsembleName = QString() ); - - static RimSummaryEnsemble* importSingleEnsembleFileSet( const QStringList& fileNames, - bool useEnsembleNameDialog, - RiaDefines::EnsembleGroupingMode groupingMode, - RiaDefines::FileType fileType, - const QString& defaultEnsembleName = QString() ); }; diff --git a/ApplicationLibCode/Commands/RicImportGridAndSummaryEnsembleDialog.cpp b/ApplicationLibCode/Commands/RicImportGridAndSummaryEnsembleDialog.cpp index d6b66fe2e8..e65adb59e2 100644 --- a/ApplicationLibCode/Commands/RicImportGridAndSummaryEnsembleDialog.cpp +++ b/ApplicationLibCode/Commands/RicImportGridAndSummaryEnsembleDialog.cpp @@ -55,7 +55,8 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RicImportGridAndSummaryEnsembleDialogResult RicImportGridAndSummaryEnsembleDialog::runDialog( QWidget* parent ) +RicImportGridAndSummaryEnsembleDialogResult + RicImportGridAndSummaryEnsembleDialog::runDialog( QWidget* parent, bool defaultGridChecked, bool defaultSummaryChecked ) { const QString pathRegistryKey = "RicImportGridAndSummaryEnsembleDialog_path"; @@ -89,6 +90,9 @@ RicImportGridAndSummaryEnsembleDialogResult RicImportGridAndSummaryEnsembleDialo dialog.m_ensembleGroupingMode->addItem( s ); } + dialog.m_createGridEnsembleCheckBox->setChecked( defaultGridChecked ); + dialog.m_createSummaryEnsembleCheckBox->setChecked( defaultSummaryChecked ); + dialog.updateEffectiveFilter(); dialog.clearFileList(); dialog.setOkButtonEnabled( false ); @@ -434,9 +438,7 @@ void RicImportGridAndSummaryEnsembleDialog::updateFileListWidget() auto mode = ensembleGroupingMode(); auto ensembleLabel = []( const QString& name, int gridCount, int summaryCount ) - { - return QString( "%1 (%2 grids, %3 summary cases)" ).arg( name ).arg( gridCount ).arg( summaryCount ); - }; + { return QString( "%1 (%2 grids, %3 summary cases)" ).arg( name ).arg( gridCount ).arg( summaryCount ); }; if ( mode == RiaDefines::EnsembleGroupingMode::NONE ) { @@ -547,7 +549,6 @@ RiaDefines::EnsembleGroupingMode RicImportGridAndSummaryEnsembleDialog::ensemble return RiaDefines::EnsembleGroupingMode::FMU_FOLDER_STRUCTURE; } - //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/Commands/RicImportGridAndSummaryEnsembleDialog.h b/ApplicationLibCode/Commands/RicImportGridAndSummaryEnsembleDialog.h index 582ca2b210..19653c2125 100644 --- a/ApplicationLibCode/Commands/RicImportGridAndSummaryEnsembleDialog.h +++ b/ApplicationLibCode/Commands/RicImportGridAndSummaryEnsembleDialog.h @@ -55,7 +55,7 @@ class RicImportGridAndSummaryEnsembleDialog : public QDialog Q_OBJECT public: - static RicImportGridAndSummaryEnsembleDialogResult runDialog( QWidget* parent ); + static RicImportGridAndSummaryEnsembleDialogResult runDialog( QWidget* parent, bool defaultGridChecked, bool defaultSummaryChecked ); private: explicit RicImportGridAndSummaryEnsembleDialog( QWidget* parent ); diff --git a/ApplicationLibCode/Commands/RicImportGridAndSummaryEnsembleFeature.cpp b/ApplicationLibCode/Commands/RicImportGridAndSummaryEnsembleFeature.cpp new file mode 100644 index 0000000000..000d58bb84 --- /dev/null +++ b/ApplicationLibCode/Commands/RicImportGridAndSummaryEnsembleFeature.cpp @@ -0,0 +1,126 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2026- 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RicImportGridAndSummaryEnsembleFeature.h" + +#include "RiaGuiApplication.h" +#include "Summary/RiaSummaryPlotTools.h" + +#include "RicImportGridAndSummaryEnsembleDialog.h" +#include "RicNewViewFeature.h" + +#include "EnsembleFileSet/RimEnsembleFileSetTools.h" +#include "Rim3dView.h" +#include "RimReservoirGridEnsemble.h" +#include "RimSummaryEnsemble.h" +#include "RimViewNameConfig.h" + +#include "RiuPlotMainWindow.h" +#include "RiuPlotMainWindowTools.h" + +#include +#include +#include +#include + +CAF_CMD_SOURCE_INIT( RicImportGridAndSummaryEnsembleFeature, "RicImportGridAndSummaryEnsembleFeature" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicImportGridAndSummaryEnsembleFeature::onActionTriggered( bool isChecked ) +{ + QPointer activeWindowBeforeImport = RiaGuiApplication::widgetToUseAsParent(); + + bool startedFromPlotWindow = ( RiaGuiApplication::activeMainWindow() == RiaGuiApplication::instance()->mainPlotWindow() ); + + auto result = RicImportGridAndSummaryEnsembleDialog::runDialog( activeWindowBeforeImport, !startedFromPlotWindow, startedFromPlotWindow ); + + if ( !result.ok ) return; + if ( !result.createGridEnsemble && !result.createSummaryEnsemble ) return; + + // Build the union of base paths (extension-stripped) from both lists so every realization + // appears exactly once. findPathPattern requires each realization number to be unique across + // the input; duplicating paths with different extensions breaks the pattern detection. + auto stripExtension = []( const QString& path ) -> QString + { + int dot = path.lastIndexOf( '.' ); + return dot != -1 ? path.left( dot ) : path; + }; + + QStringList strippedPaths; + + for ( const auto& f : result.gridFiles ) + strippedPaths << stripExtension( f ); + for ( const auto& f : result.summaryFiles ) + strippedPaths << stripExtension( f ); + + strippedPaths.removeDuplicates(); + + if ( strippedPaths.isEmpty() ) return; + + auto fileSets = RimEnsembleFileSetTools::createEnsembleFileSets( strippedPaths, result.groupingMode ); + if ( fileSets.empty() ) return; + + bool gridEnsemblesCreated = false; + if ( result.createGridEnsemble && !result.gridFiles.isEmpty() ) + { + auto gridEnsembles = RimEnsembleFileSetTools::createGridEnsemblesFromFileSets( fileSets ); + if ( !gridEnsembles.empty() ) + { + gridEnsemblesCreated = true; + auto firstEnsemble = gridEnsembles.front(); + auto cases = firstEnsemble->cases(); + if ( !cases.empty() ) + { + auto view = RicNewViewFeature::addReservoirView( cases.front(), nullptr, firstEnsemble->viewCollection() ); + if ( view ) view->nameConfig()->setAddCaseName( true ); + } + } + } + + if ( result.createSummaryEnsemble && !result.summaryFiles.isEmpty() ) + { + auto summaryEnsembles = RimEnsembleFileSetTools::createSummaryEnsemblesFromFileSets( fileSets ); + for ( auto ensemble : summaryEnsembles ) + { + RiaSummaryPlotTools::createAndAppendDefaultSummaryMultiPlot( {}, { ensemble } ); + } + if ( !summaryEnsembles.empty() ) RiuPlotMainWindowTools::showPlotMainWindow(); + } + + if ( gridEnsemblesCreated && activeWindowBeforeImport ) + { + QTimer::singleShot( 500, + activeWindowBeforeImport, + [activeWindowBeforeImport]() + { + activeWindowBeforeImport->raise(); + activeWindowBeforeImport->activateWindow(); + } ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicImportGridAndSummaryEnsembleFeature::setupActionLook( QAction* actionToSetup ) +{ + actionToSetup->setIcon( QIcon( ":/GridAndSummaryEnsemble.svg" ) ); + actionToSetup->setText( "Grid and Summary Ensemble" ); +} diff --git a/ApplicationLibCode/Commands/RicImportGridAndSummaryEnsembleFeature.h b/ApplicationLibCode/Commands/RicImportGridAndSummaryEnsembleFeature.h new file mode 100644 index 0000000000..e832de180f --- /dev/null +++ b/ApplicationLibCode/Commands/RicImportGridAndSummaryEnsembleFeature.h @@ -0,0 +1,33 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2026- 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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +//================================================================================================== +/// +//================================================================================================== +class RicImportGridAndSummaryEnsembleFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + void onActionTriggered( bool isChecked ) override; + void setupActionLook( QAction* actionToSetup ) override; +}; diff --git a/ApplicationLibCode/Commands/RicRecursiveFileSearchDialog.cpp b/ApplicationLibCode/Commands/RicRecursiveFileSearchDialog.cpp index b03c6d7eed..3bf7a4a0fb 100644 --- a/ApplicationLibCode/Commands/RicRecursiveFileSearchDialog.cpp +++ b/ApplicationLibCode/Commands/RicRecursiveFileSearchDialog.cpp @@ -770,9 +770,7 @@ void RicRecursiveFileSearchDialog::setCheckedStateChildItems( QStandardItem* par //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void RicRecursiveFileSearchDialog::findItemsMatching( QStandardItem* parentItem, - const QString& substring, - QList& matchingItems ) +void RicRecursiveFileSearchDialog::findItemsMatching( QStandardItem* parentItem, const QString& substring, QList& matchingItems ) { if ( !parentItem ) return; for ( int i = 0; i < parentItem->rowCount(); ++i ) diff --git a/ApplicationLibCode/ProjectDataModel/EnsembleFileSet/RimEnsembleFileSetTools.cpp b/ApplicationLibCode/ProjectDataModel/EnsembleFileSet/RimEnsembleFileSetTools.cpp index 4da25c239f..23fa670f0a 100644 --- a/ApplicationLibCode/ProjectDataModel/EnsembleFileSet/RimEnsembleFileSetTools.cpp +++ b/ApplicationLibCode/ProjectDataModel/EnsembleFileSet/RimEnsembleFileSetTools.cpp @@ -103,6 +103,7 @@ std::vector createGridEnsemblesFromFileSets( const st project->assignIdToCaseGroup( ensemble ); eclipseCaseColl->reservoirGridEnsembles.push_back( ensemble ); + ensemble->createGridCasesFromEnsembleFileSet(); ensemble->loadDataAndUpdate(); ensembles.push_back( ensemble ); } diff --git a/ApplicationLibCode/ProjectDataModel/RimReservoirGridEnsemble.cpp b/ApplicationLibCode/ProjectDataModel/RimReservoirGridEnsemble.cpp index f6a79ce179..b9e07db85c 100644 --- a/ApplicationLibCode/ProjectDataModel/RimReservoirGridEnsemble.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimReservoirGridEnsemble.cpp @@ -482,6 +482,14 @@ RimEclipseView* RimReservoirGridEnsemble::addViewForCase( RimEclipseCase* eclips return m_viewCollection->addView( eclipseCase ); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseViewCollection* RimReservoirGridEnsemble::viewCollection() const +{ + return m_viewCollection; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/RimReservoirGridEnsemble.h b/ApplicationLibCode/ProjectDataModel/RimReservoirGridEnsemble.h index d39c118fd6..e697955b64 100644 --- a/ApplicationLibCode/ProjectDataModel/RimReservoirGridEnsemble.h +++ b/ApplicationLibCode/ProjectDataModel/RimReservoirGridEnsemble.h @@ -106,6 +106,7 @@ public: RimEclipseView* addViewForCase( RimEclipseCase* eclipseCase ); std::vector allViews() const; std::set casesInViews() const override; + RimEclipseViewCollection* viewCollection() const; // Well target mapping void addWellTargetMapping( RimWellTargetMapping* wellTargetMapping ); diff --git a/ApplicationLibCode/UserInterface/RiuMainWindow.cpp b/ApplicationLibCode/UserInterface/RiuMainWindow.cpp index 6473b7d0a6..ea8cb03679 100644 --- a/ApplicationLibCode/UserInterface/RiuMainWindow.cpp +++ b/ApplicationLibCode/UserInterface/RiuMainWindow.cpp @@ -594,6 +594,8 @@ void RiuMainWindow::createToolBars() QToolBar* toolbar = addToolBar( tr( "Standard" ) ); toolbar->setObjectName( toolbar->windowTitle() ); toolbar->addAction( cmdFeatureMgr->action( "RicImportEclipseCaseFeature" ) ); + toolbar->addAction( cmdFeatureMgr->action( "RicImportGridAndSummaryEnsembleFeature" ) ); + toolbar->addSeparator(); toolbar->addAction( cmdFeatureMgr->action( "RicOpenProjectFeature" ) ); toolbar->addAction( cmdFeatureMgr->action( "RicSaveProjectFeature" ) ); } diff --git a/ApplicationLibCode/UserInterface/RiuMenuBarBuildTools.cpp b/ApplicationLibCode/UserInterface/RiuMenuBarBuildTools.cpp index 6c4891e435..c43784150c 100644 --- a/ApplicationLibCode/UserInterface/RiuMenuBarBuildTools.cpp +++ b/ApplicationLibCode/UserInterface/RiuMenuBarBuildTools.cpp @@ -123,6 +123,9 @@ void RiuMenuBarBuildTools::addImportMenuWithActions( QObject* parent, QMenu* men QMenu* importRoffMenu = importMenu->addMenu( QIcon( ":/Case48x48.png" ), "Roff Grid Models" ); importRoffMenu->addAction( cmdFeatureMgr->action( "RicImportRoffCaseFeature" ) ); + importMenu->addSeparator(); + importMenu->addAction( cmdFeatureMgr->action( "RicImportGridAndSummaryEnsembleFeature" ) ); + importMenu->addSeparator(); QMenu* importSummaryMenu = importMenu->addMenu( QIcon( ":/SummaryCase.svg" ), "Summary Cases" ); importSummaryMenu->addAction( cmdFeatureMgr->action( "RicImportSummaryCaseFeature" ) ); diff --git a/ApplicationLibCode/UserInterface/RiuPlotMainWindow.cpp b/ApplicationLibCode/UserInterface/RiuPlotMainWindow.cpp index f5b26a49fe..2a5784aa5d 100644 --- a/ApplicationLibCode/UserInterface/RiuPlotMainWindow.cpp +++ b/ApplicationLibCode/UserInterface/RiuPlotMainWindow.cpp @@ -393,7 +393,9 @@ QStringList RiuPlotMainWindow::toolbarCommandIds( const QString& toolbarName ) { commandIds << "RicImportEclipseCaseFeature"; commandIds << "RicImportSummaryCaseFeature"; + commandIds << "RicImportGridAndSummaryEnsembleFeature"; commandIds << "RicImportEnsembleFeature"; + commandIds << "Separator"; commandIds << "RicOpenProjectFeature"; commandIds << "RicSaveProjectFeature"; } @@ -440,7 +442,14 @@ void RiuPlotMainWindow::createToolBars() QStringList toolbarCommands = toolbarCommandIds( toolbarName ); for ( QString s : toolbarCommands ) { - toolbar->addAction( cmdFeatureMgr->action( s ) ); + if ( s.compare( "separator", Qt::CaseInsensitive ) == 0 ) + { + toolbar->addSeparator(); + } + else + { + toolbar->addAction( cmdFeatureMgr->action( s ) ); + } } if ( toolbarName == "View" ) {