diff --git a/ApplicationLibCode/CommandFileInterface/RicfExportVisibleCells.cpp b/ApplicationLibCode/CommandFileInterface/RicfExportVisibleCells.cpp index 879aa9b5ab..d75334c4fa 100644 --- a/ApplicationLibCode/CommandFileInterface/RicfExportVisibleCells.cpp +++ b/ApplicationLibCode/CommandFileInterface/RicfExportVisibleCells.cpp @@ -18,28 +18,17 @@ #include "RicfExportVisibleCells.h" -#include "RiaFilePathTools.h" -#include "RiaViewRedrawScheduler.h" +#include "RiaApplication.h" -#include "ExportCommands/RicSaveEclipseInputVisibleCellsFeature.h" #include "ExportCommands/RicSaveEclipseInputVisibleCellsUi.h" #include "RicfApplicationTools.h" #include "RicfCommandFileExecutor.h" +#include "RicfCommandForwarding.h" -#include "RiaApplication.h" -#include "RiaLogging.h" - -#include "RimEclipseCase.h" -#include "RimEclipseCaseCollection.h" -#include "RimEclipseCellColors.h" #include "RimEclipseView.h" -#include "RimOilField.h" -#include "RimProject.h" - -#include "RifEclipseInputFileTools.h" +#include "RimcEclipseView.h" #include "cafPdmFieldScriptingCapability.h" -#include #include @@ -77,12 +66,13 @@ RicfExportVisibleCells::RicfExportVisibleCells() //-------------------------------------------------------------------------------------------------- caf::PdmScriptResponse RicfExportVisibleCells::execute() { + const QString commandName = classKeyword(); + if ( m_caseId < 0 || ( m_viewName().isEmpty() && m_viewId() < 0 ) ) { - QString error( "exportVisibleCells: CaseId or view name or view id not specified" ); - RiaLogging::error( error.toStdString() ); - return caf::PdmScriptResponse( caf::PdmScriptResponse::COMMAND_ERROR, error ); + return RicfForwarding::errorResponse( "CaseId or view name or view id not specified", commandName ); } + RimEclipseView* eclipseView = nullptr; if ( m_viewId() >= 0 ) { @@ -94,45 +84,33 @@ caf::PdmScriptResponse RicfExportVisibleCells::execute() } if ( !eclipseView ) { - QString error( QString( "exportVisibleCells: Could not find view of id %1 or named '%2' in case ID %3" ) - .arg( m_viewId() ) - .arg( m_viewName() ) - .arg( m_caseId() ) ); - RiaLogging::error( error.toStdString() ); - return caf::PdmScriptResponse( caf::PdmScriptResponse::COMMAND_ERROR, error ); + return RicfForwarding::errorResponse( QString( "Could not find view of id %1 or named '%2' in case ID %3" ) + .arg( m_viewId() ) + .arg( m_viewName() ) + .arg( m_caseId() ), + commandName ); } + // Resolve the default export folder from the command file executor state. The Rimc method requires an explicit file. QString exportFolder = RicfCommandFileExecutor::instance()->getExportPath( RicfCommandFileExecutor::ExportType::CELLS ); if ( exportFolder.isNull() ) { exportFolder = RiaApplication::instance()->currentProjectPath(); } - - RiaViewRedrawScheduler::instance()->clearViewsScheduledForUpdate(); - - RicSaveEclipseInputVisibleCellsUi exportSettings; - buildExportSettings( exportFolder, &exportSettings ); - RicSaveEclipseInputVisibleCellsFeature::executeCommand( eclipseView, exportSettings, "exportVisibleCells" ); - - return caf::PdmScriptResponse(); -} - -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RicfExportVisibleCells::buildExportSettings( const QString& exportFolder, RicSaveEclipseInputVisibleCellsUi* exportSettings ) -{ QDir baseDir( exportFolder ); - exportSettings->exportFilename = baseDir.absoluteFilePath( QString( "%1.grdecl" ).arg( m_exportKeyword().text() ) ); - if ( m_exportKeyword == ExportKeyword::FLUXNUM ) - exportSettings->exportKeyword = RicSaveEclipseInputVisibleCellsUi::FLUXNUM; - else if ( m_exportKeyword == ExportKeyword::MULTNUM ) - exportSettings->exportKeyword = RicSaveEclipseInputVisibleCellsUi::MULTNUM; + RicSaveEclipseInputVisibleCellsUi::ExportKeyword exportKeyword = RicSaveEclipseInputVisibleCellsUi::FLUXNUM; + if ( m_exportKeyword == ExportKeyword::MULTNUM ) + exportKeyword = RicSaveEclipseInputVisibleCellsUi::MULTNUM; else if ( m_exportKeyword == ExportKeyword::ACTNUM ) - exportSettings->exportKeyword = RicSaveEclipseInputVisibleCellsUi::ACTNUM; + exportKeyword = RicSaveEclipseInputVisibleCellsUi::ACTNUM; - exportSettings->visibleActiveCellsValue = m_visibleActiveCellsValue; - exportSettings->hiddenActiveCellsValue = m_hiddenActiveCellsValue; - exportSettings->inactiveCellsValue = m_inactiveCellsValue; + RimEclipseView_exportVisibleCells method( eclipseView ); + method.setExportFile( baseDir.absoluteFilePath( QString( "%1.grdecl" ).arg( m_exportKeyword().text() ) ) ); + method.setExportKeyword( exportKeyword ); + method.setVisibleActiveCellsValue( m_visibleActiveCellsValue() ); + method.setHiddenActiveCellsValue( m_hiddenActiveCellsValue() ); + method.setInactiveCellsValue( m_inactiveCellsValue() ); + + return RicfForwarding::toScriptResponse( method.execute(), commandName ); } diff --git a/ApplicationLibCode/CommandFileInterface/RicfExportVisibleCells.h b/ApplicationLibCode/CommandFileInterface/RicfExportVisibleCells.h index c0eb6177ad..bf04acb44a 100644 --- a/ApplicationLibCode/CommandFileInterface/RicfExportVisibleCells.h +++ b/ApplicationLibCode/CommandFileInterface/RicfExportVisibleCells.h @@ -25,7 +25,6 @@ #include "cafPdmField.h" class RimEclipseView; -class RicSaveEclipseInputVisibleCellsUi; //================================================================================================== // @@ -49,8 +48,6 @@ public: caf::PdmScriptResponse execute() override; private: - void buildExportSettings( const QString& exportFolder, RicSaveEclipseInputVisibleCellsUi* exportSettings ); - caf::PdmField m_caseId; caf::PdmField m_viewId; caf::PdmField m_viewName; diff --git a/ApplicationLibCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsFeature.cpp b/ApplicationLibCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsFeature.cpp index d5bf19cc96..3c937727ab 100644 --- a/ApplicationLibCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsFeature.cpp +++ b/ApplicationLibCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsFeature.cpp @@ -71,6 +71,23 @@ void RicSaveEclipseInputVisibleCellsFeature::executeCommand( RimEclipseView* const RicSaveEclipseInputVisibleCellsUi& exportSettings, const QString& logPrefix ) { + if ( auto result = exportVisibleCells( view, exportSettings ); !result ) + { + RiaLogging::error( std::format( "{}: {}", logPrefix, result.error() ) ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::expected + RicSaveEclipseInputVisibleCellsFeature::exportVisibleCells( RimEclipseView* view, const RicSaveEclipseInputVisibleCellsUi& exportSettings ) +{ + if ( !view || !view->eclipseCase() || !view->eclipseCase()->eclipseCaseData() ) + { + return std::unexpected( "The view has no case data." ); + } + std::vector values; cvf::UByteArray visibleCells; view->calculateCurrentTotalCellVisibility( &visibleCells, view->currentTimeStep() ); @@ -97,8 +114,7 @@ void RicSaveEclipseInputVisibleCellsFeature::executeCommand( RimEclipseView* QFile exportFile( exportSettings.exportFilename ); if ( !exportFile.open( QIODevice::WriteOnly | QIODevice::Text ) ) { - RiaLogging::error( std::format( "{}: Unable to open file '{}' for writing.", logPrefix, exportSettings.exportFilename() ) ); - return; + return std::unexpected( QString( "Unable to open file '%1' for writing." ).arg( exportSettings.exportFilename() ) ); } int valuesPerRow = 5; @@ -107,6 +123,7 @@ void RicSaveEclipseInputVisibleCellsFeature::executeCommand( RimEclipseView* exportSettings.exportKeyword().text(), values, valuesPerRow ); + return {}; } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsFeature.h b/ApplicationLibCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsFeature.h index 701ed4ce66..b61dff8bd7 100644 --- a/ApplicationLibCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsFeature.h +++ b/ApplicationLibCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsFeature.h @@ -20,6 +20,8 @@ #include "cafCmdFeature.h" +#include + class RimEclipseView; class RicSaveEclipseInputVisibleCellsUi; @@ -33,6 +35,7 @@ class RicSaveEclipseInputVisibleCellsFeature : public caf::CmdFeature public: static void openDialogAndExecuteCommand( RimEclipseView* view ); static void executeCommand( RimEclipseView* view, const RicSaveEclipseInputVisibleCellsUi& exportSettings, const QString& logPrefix ); + static std::expected exportVisibleCells( RimEclipseView* view, const RicSaveEclipseInputVisibleCellsUi& exportSettings ); protected: bool isCommandEnabled() const override; diff --git a/ApplicationLibCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsUi.cpp b/ApplicationLibCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsUi.cpp index 8ed93cd536..725260e194 100644 --- a/ApplicationLibCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsUi.cpp +++ b/ApplicationLibCode/Commands/ExportCommands/RicSaveEclipseInputVisibleCellsUi.cpp @@ -21,6 +21,7 @@ #include "RiaApplication.h" #include "RiaPreferences.h" +#include "cafPdmScriptEnumNameRegistry.h" #include "cafPdmUiFilePathEditor.h" #include @@ -37,6 +38,19 @@ void RicSaveEclipseInputVisibleCellsUi::ExportKeywordEnum::setUp() } } // namespace caf +namespace +{ +// Pin the Python StrEnum class name for the export keyword used by RimEclipseView_exportVisibleCells +struct RegisterScriptEnumNames +{ + RegisterScriptEnumNames() + { + caf::PdmScriptEnumNameRegistry::registerName( "VisibleCellsExportKeyword" ); + } +}; +const RegisterScriptEnumNames s_registerScriptEnumNames; +} // namespace + CAF_PDM_SOURCE_INIT( RicSaveEclipseInputVisibleCellsUi, "RicSaveEclipseInputVisibleCellsUi" ); //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModelCommands/RimcEclipseView.cpp b/ApplicationLibCode/ProjectDataModelCommands/RimcEclipseView.cpp index a987ed615a..064e124487 100644 --- a/ApplicationLibCode/ProjectDataModelCommands/RimcEclipseView.cpp +++ b/ApplicationLibCode/ProjectDataModelCommands/RimcEclipseView.cpp @@ -19,6 +19,9 @@ #include "RimcEclipseView.h" #include "ExportCommands/RicEclipseCellResultToFileImpl.h" +#include "ExportCommands/RicSaveEclipseInputVisibleCellsFeature.h" + +#include "RiaViewRedrawScheduler.h" #include "RigResultAccessor.h" #include "RigResultAccessorFactory.h" @@ -181,3 +184,105 @@ QString RimEclipseView_exportCurrentProperty::defaultFileBaseName( const RimEcli return caf::Utils::makeValidFileBasename( fileName ); } + +CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimEclipseView, RimEclipseView_exportVisibleCells, "exportVisibleCells" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseView_exportVisibleCells::RimEclipseView_exportVisibleCells( caf::PdmObjectHandle* self ) + : caf::PdmVoidObjectMethod( self ) +{ + CAF_PDM_InitObject( "Export Visible Cells", "", "", "Export a GRDECL keyword with one value per cell based on cell visibility in the view" ); + + CAF_PDM_InitScriptableField( &m_exportFile, "ExportFile", QString(), "Export File", "", "", "Full path of the file to write" ); + CAF_PDM_InitScriptableField( &m_exportKeyword, + "ExportKeyword", + RicSaveEclipseInputVisibleCellsUi::FLUXNUM, + "Export Keyword", + "", + "", + "GRDECL keyword to write" ); + CAF_PDM_InitScriptableField( &m_visibleActiveCellsValue, + "VisibleActiveCellsValue", + 1, + "Visible Active Cells Value", + "", + "", + "Value for visible active cells" ); + CAF_PDM_InitScriptableField( &m_hiddenActiveCellsValue, + "HiddenActiveCellsValue", + 0, + "Hidden Active Cells Value", + "", + "", + "Value for hidden active cells" ); + CAF_PDM_InitScriptableField( &m_inactiveCellsValue, "InactiveCellsValue", 0, "Inactive Cells Value", "", "", "Value for inactive cells" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseView_exportVisibleCells::setExportFile( const QString& exportFile ) +{ + m_exportFile = exportFile; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseView_exportVisibleCells::setExportKeyword( RicSaveEclipseInputVisibleCellsUi::ExportKeyword exportKeyword ) +{ + m_exportKeyword = exportKeyword; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseView_exportVisibleCells::setVisibleActiveCellsValue( int value ) +{ + m_visibleActiveCellsValue = value; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseView_exportVisibleCells::setHiddenActiveCellsValue( int value ) +{ + m_hiddenActiveCellsValue = value; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimEclipseView_exportVisibleCells::setInactiveCellsValue( int value ) +{ + m_inactiveCellsValue = value; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::expected RimEclipseView_exportVisibleCells::execute() +{ + auto* view = self(); + if ( !view ) return std::unexpected( "No view is available." ); + + if ( m_exportFile().isEmpty() ) return std::unexpected( "No export file specified." ); + + RiaViewRedrawScheduler::instance()->clearViewsScheduledForUpdate(); + + RicSaveEclipseInputVisibleCellsUi exportSettings; + exportSettings.exportFilename = m_exportFile(); + exportSettings.exportKeyword = m_exportKeyword(); + exportSettings.visibleActiveCellsValue = m_visibleActiveCellsValue(); + exportSettings.hiddenActiveCellsValue = m_hiddenActiveCellsValue(); + exportSettings.inactiveCellsValue = m_inactiveCellsValue(); + + if ( auto result = RicSaveEclipseInputVisibleCellsFeature::exportVisibleCells( view, exportSettings ); !result ) + { + return std::unexpected( result.error() ); + } + + return nullptr; +} diff --git a/ApplicationLibCode/ProjectDataModelCommands/RimcEclipseView.h b/ApplicationLibCode/ProjectDataModelCommands/RimcEclipseView.h index c1c9c5641c..ff633be7fe 100644 --- a/ApplicationLibCode/ProjectDataModelCommands/RimcEclipseView.h +++ b/ApplicationLibCode/ProjectDataModelCommands/RimcEclipseView.h @@ -18,6 +18,9 @@ #pragma once +#include "ExportCommands/RicSaveEclipseInputVisibleCellsUi.h" + +#include "cafAppEnum.h" #include "cafPdmField.h" #include "cafPdmObjectHandle.h" #include "cafPdmObjectMethod.h" @@ -68,3 +71,30 @@ private: caf::PdmField m_exportFile; caf::PdmField m_undefinedValue; }; + +//================================================================================================== +/// Export a GRDECL keyword (FLUXNUM, MULTNUM or ACTNUM) with one value per cell based on the cell +/// visibility in the view at the current time step. +//================================================================================================== +class RimEclipseView_exportVisibleCells : public caf::PdmVoidObjectMethod +{ + CAF_PDM_HEADER_INIT; + +public: + RimEclipseView_exportVisibleCells( caf::PdmObjectHandle* self ); + + void setExportFile( const QString& exportFile ); + void setExportKeyword( RicSaveEclipseInputVisibleCellsUi::ExportKeyword exportKeyword ); + void setVisibleActiveCellsValue( int value ); + void setHiddenActiveCellsValue( int value ); + void setInactiveCellsValue( int value ); + + std::expected execute() override; + +private: + caf::PdmField m_exportFile; + caf::PdmField> m_exportKeyword; + caf::PdmField m_visibleActiveCellsValue; + caf::PdmField m_hiddenActiveCellsValue; + caf::PdmField m_inactiveCellsValue; +}; diff --git a/GrpcInterface/Python/rips/tests/test_properties.py b/GrpcInterface/Python/rips/tests/test_properties.py index 0c55f379b0..4d3dc74eec 100644 --- a/GrpcInterface/Python/rips/tests/test_properties.py +++ b/GrpcInterface/Python/rips/tests/test_properties.py @@ -303,3 +303,31 @@ def test_export_current_property(rips_instance, initialize_test): with pytest.raises(rips.RipsError): view.export_current_property() + + +def test_export_visible_cells(rips_instance, initialize_test): + case_path = dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID" + case = rips_instance.project.load_case(case_path) + view = case.create_view() + with tempfile.TemporaryDirectory(prefix="rips") as tmpdirname: + export_file = os.path.join(tmpdirname, "fluxnum.grdecl") + view.export_visible_cells(export_file=export_file) + assert os.path.exists(export_file) + with open(export_file) as f: + assert "FLUXNUM" in f.read(200) + + export_file = os.path.join(tmpdirname, "actnum.grdecl") + view.export_visible_cells( + export_file=export_file, + export_keyword=rips.VisibleCellsExportKeyword.ACTNUM, + visible_active_cells_value=2, + ) + with open(export_file) as f: + content = f.read() + assert "ACTNUM" in content[:200] + # Note: without a GUI no cells are visible, so the exported values are not asserted + values = content.split("ACTNUM")[1].split("/")[0].split() + assert len(values) > 0 + + with pytest.raises(rips.RipsError): + view.export_visible_cells() diff --git a/GrpcInterface/Python/rips/view.py b/GrpcInterface/Python/rips/view.py index 63c7577ea8..1d3c7fffc6 100644 --- a/GrpcInterface/Python/rips/view.py +++ b/GrpcInterface/Python/rips/view.py @@ -129,36 +129,6 @@ def export_sim_well_fracture_completions( ) -@add_method(View) -def export_visible_cells( - self, - export_keyword="FLUXNUM", - visible_active_cells_value=1, - hidden_active_cells_value=0, - inactive_cells_value=0, -): - """Export special properties for all visible cells. - - Arguments: - export_keyword (string): The keyword to export. - Choices: 'FLUXNUM' or 'MULTNUM'. Default: 'FLUXNUM' - visible_active_cells_value (int): Value to export forvisible active cells. Default: 1 - hidden_active_cells_value (int): Value to export for hidden active cells. Default: 0 - inactive_cells_value (int): Value to export for inactive cells. Default: 0 - """ - case_id = self.case().id - return self._execute_command( - exportVisibleCells=Cmd.ExportVisibleCellsRequest( - caseId=case_id, - viewId=self.id, - exportKeyword=export_keyword, - visibleActiveCellsValue=visible_active_cells_value, - hiddenActiveCellsValue=hidden_active_cells_value, - inactiveCellsValue=inactive_cells_value, - ) - ) - - @add_method(View) def export_property(self, undefined_value=0.0): """Export the current Eclipse property from the view