diff --git a/ApplicationLibCode/ProjectDataModelCommands/RimcProject.cpp b/ApplicationLibCode/ProjectDataModelCommands/RimcProject.cpp index 6f8e6e6caf..fc43a526a3 100644 --- a/ApplicationLibCode/ProjectDataModelCommands/RimcProject.cpp +++ b/ApplicationLibCode/ProjectDataModelCommands/RimcProject.cpp @@ -28,6 +28,7 @@ #include "RiaPreferencesGrid.h" #include "RiaQStringFormatter.h" #include "RiaRegressionTestRunner.h" +#include "Summary/RiaSummaryTools.h" #include "ExportCommands/RicSnapshotAllPlotsToFileFeature.h" #include "ExportCommands/RicSnapshotAllViewsToFileFeature.h" @@ -54,6 +55,7 @@ #include "RimProject.h" #include "RimSummaryCase.h" #include "RimSummaryCaseMainCollection.h" +#include "RimSummaryEnsemble.h" #include "RimSurfaceCollection.h" #include "RimTools.h" #include "RimValveTemplateCollection.h" @@ -132,6 +134,64 @@ QString RimProject_importSummaryCase::classKeywordReturnedType() const return RimFileSummaryCase::classKeywordStatic(); } +CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimProject, RimProject_importSummaryEnsemble, "importSummaryEnsemble" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimProject_importSummaryEnsemble::RimProject_importSummaryEnsemble( caf::PdmObjectHandle* self ) + : PdmObjectCreationMethod( self ) +{ + CAF_PDM_InitObject( "Import Summary Ensemble", "", "", "Import summary files as one ensemble" ); + + CAF_PDM_InitScriptableFieldNoDefault( &m_fileNames, "FileNames", "", "", "", "Summary files (SMSPEC), one for each realization" ); + CAF_PDM_InitScriptableFieldNoDefault( &m_ensembleName, "EnsembleName", "", "", "", "Ensemble name. Automatically generated if empty" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::expected RimProject_importSummaryEnsemble::execute() +{ + QStringList summaryFileNames; + for ( const QString& fileName : m_fileNames() ) + { + QString absolutePath = fileName; + if ( !QFileInfo( absolutePath ).exists() ) + { + absolutePath = QDir( RiaApplication::instance()->startDir() ).absoluteFilePath( fileName ); + } + summaryFileNames.push_back( absolutePath ); + } + + if ( summaryFileNames.isEmpty() ) return std::unexpected( "No summary files specified." ); + + RiaEnsembleImportTools::CreateConfig createConfig{ .fileType = RiaDefines::FileType::SMSPEC, .ensembleOrGroup = true, .allowDialogs = false }; + auto newCases = RiaEnsembleImportTools::createSummaryCasesFromFiles( summaryFileNames, createConfig ); + if ( newCases.empty() ) return std::unexpected( "Unable to import any of the summary files." ); + + auto* mainCollection = RiaSummaryTools::summaryCaseMainCollection(); + if ( !mainCollection ) return std::unexpected( "No summary case collection found." ); + + auto ensemble = mainCollection->addEnsemble( newCases, m_ensembleName(), true ); + + // The name template is only used when auto naming is disabled + if ( !m_ensembleName().isEmpty() ) ensemble->setAutoName( false ); + RiaSummaryTools::updateSummaryEnsembleNames(); + + mainCollection->updateConnectedEditors(); + + return ensemble; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimProject_importSummaryEnsemble::classKeywordReturnedType() const +{ + return RimSummaryEnsemble::classKeywordStatic(); +} + CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimProject, RimProject_summaryCase, "summaryCase" ); //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModelCommands/RimcProject.h b/ApplicationLibCode/ProjectDataModelCommands/RimcProject.h index 9d912ad32a..da736b8a92 100644 --- a/ApplicationLibCode/ProjectDataModelCommands/RimcProject.h +++ b/ApplicationLibCode/ProjectDataModelCommands/RimcProject.h @@ -52,6 +52,24 @@ private: caf::PdmField m_fileName; }; +//================================================================================================== +/// +//================================================================================================== +class RimProject_importSummaryEnsemble : public caf::PdmObjectCreationMethod +{ + CAF_PDM_HEADER_INIT; + +public: + RimProject_importSummaryEnsemble( caf::PdmObjectHandle* self ); + + std::expected execute() override; + QString classKeywordReturnedType() const override; + +private: + caf::PdmField> m_fileNames; + caf::PdmField m_ensembleName; +}; + //================================================================================================== /// //================================================================================================== diff --git a/GrpcInterface/Python/rips/__init__.py b/GrpcInterface/Python/rips/__init__.py index 1df5aa4178..fa7ecc1907 100644 --- a/GrpcInterface/Python/rips/__init__.py +++ b/GrpcInterface/Python/rips/__init__.py @@ -29,6 +29,7 @@ from .exception import RipsError as RipsError # noqa: E402 from .surface import RegularSurface as RegularSurface # noqa: E402 from . import well_events as well_events # noqa: F401, E402 from . import category_mapping as category_mapping # noqa: F401, E402 +from . import summary_ensemble as summary_ensemble # noqa: F401, E402 __all__: List[str] = [] for key in class_dict(): # noqa: F405 diff --git a/GrpcInterface/Python/rips/project.py b/GrpcInterface/Python/rips/project.py index cbd1d0f90a..a11ac2c605 100644 --- a/GrpcInterface/Python/rips/project.py +++ b/GrpcInterface/Python/rips/project.py @@ -31,6 +31,8 @@ from .resinsight_classes import ( SnapshotContentType, SnapshotFileFormat, SummaryCase, + SummaryEnsemble, + SummaryPlotCollection, WellPath, ) @@ -624,3 +626,26 @@ def remove_key_values(self, key): """ request = KeyValueStore_pb2.KeyValueStoreRemoveRequest(name=key) self.__key_value_store_stub.RemoveValue(request) + + +@add_method(Project) +def summary_ensembles(self: Project) -> List[SummaryEnsemble]: + """Get all summary ensembles in the project + + Returns: + List[SummaryEnsemble]: Summary case groups flagged as ensembles + """ + return [group for group in self.descendants(SummaryEnsemble) if group.is_ensemble] + + +@add_method(Project) +def summary_plot_collection(self: Project) -> SummaryPlotCollection: + """Get the summary plot collection of the project + + Returns: + SummaryPlotCollection: The collection used to create summary plots + """ + collections = self.descendants(SummaryPlotCollection) + if not collections: + raise RipsError("No summary plot collection found in the project") + return collections[0]