diff --git a/ApplicationCode/Application/RiaGuiApplication.cpp b/ApplicationCode/Application/RiaGuiApplication.cpp index dc14cd24da..8444127568 100644 --- a/ApplicationCode/Application/RiaGuiApplication.cpp +++ b/ApplicationCode/Application/RiaGuiApplication.cpp @@ -832,7 +832,7 @@ RiaApplication::ApplicationStatus RiaGuiApplication::handleArguments( cvf::Progr // 2016-11-09 : Location of snapshot folder was previously located in 'snapshot' folder // relative to current working folder. Now harmonized to behave as RiuMainWindow::slotSnapshotAllViewsToFile() QString absolutePathToSnapshotDir = createAbsolutePathFromProjectRelativePath( "snapshots" ); - RicSnapshotAllViewsToFileFeature::exportSnapshotOfAllViewsIntoFolder( absolutePathToSnapshotDir ); + RicSnapshotAllViewsToFileFeature::exportSnapshotOfViewsIntoFolder( absolutePathToSnapshotDir ); mainWnd->loadWinGeoAndDockToolBarLayout(); } @@ -1799,7 +1799,7 @@ void RiaGuiApplication::runMultiCaseSnapshots( const QString& templateProj bool loadOk = loadProject( templateProjectFileName, PLA_NONE, &modifier ); if ( loadOk ) { - RicSnapshotAllViewsToFileFeature::exportSnapshotOfAllViewsIntoFolder( snapshotFolderName ); + RicSnapshotAllViewsToFileFeature::exportSnapshotOfViewsIntoFolder( snapshotFolderName ); } } diff --git a/ApplicationCode/Application/Tools/RiaRegressionTestRunner.cpp b/ApplicationCode/Application/Tools/RiaRegressionTestRunner.cpp index 56fc7214c5..9636e16939 100644 --- a/ApplicationCode/Application/Tools/RiaRegressionTestRunner.cpp +++ b/ApplicationCode/Application/Tools/RiaRegressionTestRunner.cpp @@ -208,7 +208,7 @@ void RiaRegressionTestRunner::runRegressionTest() resizePlotWindows(); QString fullPathGeneratedFolder = testCaseFolder.absoluteFilePath( generatedFolderName ); - RicSnapshotAllViewsToFileFeature::exportSnapshotOfAllViewsIntoFolder( fullPathGeneratedFolder ); + RicSnapshotAllViewsToFileFeature::exportSnapshotOfViewsIntoFolder( fullPathGeneratedFolder ); RicSnapshotAllPlotsToFileFeature::exportSnapshotOfAllPlotsIntoFolder( fullPathGeneratedFolder ); diff --git a/ApplicationCode/CommandFileInterface/RicfApplicationTools.cpp b/ApplicationCode/CommandFileInterface/RicfApplicationTools.cpp index d6f5fd9cfc..75c3e8d5cd 100644 --- a/ApplicationCode/CommandFileInterface/RicfApplicationTools.cpp +++ b/ApplicationCode/CommandFileInterface/RicfApplicationTools.cpp @@ -135,3 +135,25 @@ RimEclipseView* RicfApplicationTools::viewFromCaseIdAndViewName( int caseId, con } return nullptr; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimEclipseView* RicfApplicationTools::viewFromCaseIdAndViewId( int caseId, int viewId ) +{ + for ( RimEclipseCase* c : RiaApplication::instance()->project()->eclipseCases() ) + { + if ( c->caseId() == caseId ) + { + for ( auto v : c->views() ) + { + auto eclipseView = dynamic_cast( v ); + if ( eclipseView && eclipseView->id() == viewId ) + { + return eclipseView; + } + } + } + } + return nullptr; +} diff --git a/ApplicationCode/CommandFileInterface/RicfApplicationTools.h b/ApplicationCode/CommandFileInterface/RicfApplicationTools.h index 8cb9fc295d..74c9a02184 100644 --- a/ApplicationCode/CommandFileInterface/RicfApplicationTools.h +++ b/ApplicationCode/CommandFileInterface/RicfApplicationTools.h @@ -37,6 +37,7 @@ public: static std::vector wellPathsFromNames( const QStringList& wellPathNames, QStringList* wellsNotFound ); static RimEclipseCase* caseFromId( int caseId ); static RimEclipseView* viewFromCaseIdAndViewName( int caseId, const QString& viewName ); + static RimEclipseView* viewFromCaseIdAndViewId( int caseId, int viewId ); static std::vector toStringVector( const QStringList& stringList ); static QStringList toQStringList( const std::vector& v ); diff --git a/ApplicationCode/CommandFileInterface/RicfExportPropertyInViews.cpp b/ApplicationCode/CommandFileInterface/RicfExportPropertyInViews.cpp index 359ac0992e..bde8e8355e 100644 --- a/ApplicationCode/CommandFileInterface/RicfExportPropertyInViews.cpp +++ b/ApplicationCode/CommandFileInterface/RicfExportPropertyInViews.cpp @@ -48,6 +48,7 @@ CAF_PDM_SOURCE_INIT( RicfExportPropertyInViews, "exportPropertyInViews" ); RicfExportPropertyInViews::RicfExportPropertyInViews() { RICF_InitField( &m_caseId, "caseId", -1, "Case ID", "", "", "" ); + RICF_InitField( &m_viewIds, "viewIds", std::vector(), "View IDs", "", "", "" ); RICF_InitField( &m_viewNames, "viewNames", std::vector(), "View Names", "", "", "" ); RICF_InitField( &m_undefinedValue, "undefinedValue", 0.0, "Undefined Value", "", "", "" ); } @@ -74,22 +75,35 @@ RicfCommandResponse RicfExportPropertyInViews::execute() RimEclipseView* view = dynamic_cast( v ); if ( !view ) continue; - if ( m_viewNames().empty() ) + if ( m_viewNames().empty() && m_viewIds().empty() ) { viewsForExport.push_back( view ); } else { - bool matchingName = false; - for ( const auto& viewName : m_viewNames() ) + bool matchingIdOrName = false; + + for ( auto viewId : m_viewIds() ) { - if ( view->name().compare( viewName, Qt::CaseInsensitive ) == 0 ) + if ( view->id() == viewId ) { - matchingName = true; + matchingIdOrName = true; + break; } } - if ( matchingName ) + if ( !matchingIdOrName ) + { + for ( const auto& viewName : m_viewNames() ) + { + if ( view->name().compare( viewName, Qt::CaseInsensitive ) == 0 ) + { + matchingIdOrName = true; + } + } + } + + if ( matchingIdOrName ) { viewsForExport.push_back( view ); } diff --git a/ApplicationCode/CommandFileInterface/RicfExportPropertyInViews.h b/ApplicationCode/CommandFileInterface/RicfExportPropertyInViews.h index 896d489582..8e5a60d179 100644 --- a/ApplicationCode/CommandFileInterface/RicfExportPropertyInViews.h +++ b/ApplicationCode/CommandFileInterface/RicfExportPropertyInViews.h @@ -44,6 +44,7 @@ public: private: caf::PdmField m_caseId; + caf::PdmField> m_viewIds; caf::PdmField> m_viewNames; caf::PdmField m_undefinedValue; }; diff --git a/ApplicationCode/CommandFileInterface/RicfExportSimWellFractureCompletions.cpp b/ApplicationCode/CommandFileInterface/RicfExportSimWellFractureCompletions.cpp index 292efbcf46..c057f42e4c 100644 --- a/ApplicationCode/CommandFileInterface/RicfExportSimWellFractureCompletions.cpp +++ b/ApplicationCode/CommandFileInterface/RicfExportSimWellFractureCompletions.cpp @@ -45,6 +45,7 @@ CAF_PDM_SOURCE_INIT( RicfExportSimWellFractureCompletions, "exportSimWellFractur RicfExportSimWellFractureCompletions::RicfExportSimWellFractureCompletions() { RICF_InitField( &m_caseId, "caseId", -1, "Case ID", "", "", "" ); + RICF_InitField( &m_viewId, "viewId", -1, "View ID", "", "", "" ); RICF_InitField( &m_viewName, "viewName", QString( "" ), "View Name", "", "", "" ); RICF_InitField( &m_timeStep, "timeStep", -1, "Time Step Index", "", "", "" ); RICF_InitField( &m_simWellNames, "simulationWellNames", std::vector(), "Simulation Well Names", "", "", "" ); @@ -94,17 +95,19 @@ RicfCommandResponse RicfExportSimWellFractureCompletions::execute() for ( Rim3dView* v : exportSettings->caseToApply->views() ) { RimEclipseView* eclipseView = dynamic_cast( v ); - if ( eclipseView && eclipseView->name() == m_viewName() ) + if ( eclipseView && ( eclipseView->id() == m_viewId() || eclipseView->name() == m_viewName() ) ) { views.push_back( eclipseView ); } } if ( views.empty() ) { - QString error = QString( - "exportSimWellCompletions: Could not find any views named \"%1\" in the case with ID %2" ) - .arg( m_viewName ) - .arg( m_caseId() ); + QString error = + QString( + "exportSimWellCompletions: Could not find any views with id %1 or named \"%2\" in the case with ID %3" ) + .arg( m_viewId ) + .arg( m_viewName ) + .arg( m_caseId() ); RiaLogging::error( error ); return RicfCommandResponse( RicfCommandResponse::COMMAND_ERROR, error ); } diff --git a/ApplicationCode/CommandFileInterface/RicfExportSimWellFractureCompletions.h b/ApplicationCode/CommandFileInterface/RicfExportSimWellFractureCompletions.h index 97f39efc39..b2e907d895 100644 --- a/ApplicationCode/CommandFileInterface/RicfExportSimWellFractureCompletions.h +++ b/ApplicationCode/CommandFileInterface/RicfExportSimWellFractureCompletions.h @@ -41,6 +41,7 @@ public: private: caf::PdmField m_caseId; + caf::PdmField m_viewId; caf::PdmField m_viewName; caf::PdmField m_timeStep; caf::PdmField> m_simWellNames; diff --git a/ApplicationCode/CommandFileInterface/RicfExportSnapshots.cpp b/ApplicationCode/CommandFileInterface/RicfExportSnapshots.cpp index 54bf906a3b..9a42c48509 100644 --- a/ApplicationCode/CommandFileInterface/RicfExportSnapshots.cpp +++ b/ApplicationCode/CommandFileInterface/RicfExportSnapshots.cpp @@ -52,6 +52,7 @@ RicfExportSnapshots::RicfExportSnapshots() RICF_InitField( &m_type, "type", RicfExportSnapshots::SnapshotsTypeEnum(), "Type", "", "", "" ); RICF_InitField( &m_prefix, "prefix", QString(), "Prefix", "", "", "" ); RICF_InitField( &m_caseId, "caseId", -1, "Case Id", "", "", "" ); + RICF_InitField( &m_viewId, "viewId", -1, "View Id", "", "", "" ); } //-------------------------------------------------------------------------------------------------- @@ -80,9 +81,10 @@ RicfCommandResponse RicfExportSnapshots::execute() } if ( m_type == RicfExportSnapshots::VIEWS || m_type == RicfExportSnapshots::ALL ) { - RicSnapshotAllViewsToFileFeature::exportSnapshotOfAllViewsIntoFolder( absolutePathToSnapshotDir, - m_prefix, - m_caseId() ); + RicSnapshotAllViewsToFileFeature::exportSnapshotOfViewsIntoFolder( absolutePathToSnapshotDir, + m_prefix, + m_caseId(), + m_viewId() ); } if ( m_type == RicfExportSnapshots::PLOTS || m_type == RicfExportSnapshots::ALL ) { diff --git a/ApplicationCode/CommandFileInterface/RicfExportSnapshots.h b/ApplicationCode/CommandFileInterface/RicfExportSnapshots.h index 47aa2123fa..bbad3c84ab 100644 --- a/ApplicationCode/CommandFileInterface/RicfExportSnapshots.h +++ b/ApplicationCode/CommandFileInterface/RicfExportSnapshots.h @@ -51,4 +51,5 @@ private: caf::PdmField m_type; caf::PdmField m_prefix; caf::PdmField m_caseId; + caf::PdmField m_viewId; }; diff --git a/ApplicationCode/CommandFileInterface/RicfExportVisibleCells.cpp b/ApplicationCode/CommandFileInterface/RicfExportVisibleCells.cpp index 636fcdae71..85a542a22b 100644 --- a/ApplicationCode/CommandFileInterface/RicfExportVisibleCells.cpp +++ b/ApplicationCode/CommandFileInterface/RicfExportVisibleCells.cpp @@ -64,6 +64,7 @@ void AppEnum::setUp() RicfExportVisibleCells::RicfExportVisibleCells() { RICF_InitField( &m_caseId, "caseId", -1, "Case ID", "", "", "" ); + RICF_InitField( &m_viewId, "viewId", -1, "View ID", "", "", "" ); RICF_InitField( &m_viewName, "viewName", QString(), "View Name", "", "", "" ); RICF_InitField( &m_exportKeyword, "exportKeyword", @@ -82,18 +83,27 @@ RicfExportVisibleCells::RicfExportVisibleCells() //-------------------------------------------------------------------------------------------------- RicfCommandResponse RicfExportVisibleCells::execute() { - if ( m_caseId < 0 || m_viewName().isEmpty() ) + if ( m_caseId < 0 || ( m_viewName().isEmpty() && m_viewId() < 0 ) ) { - QString error( "exportVisibleCells: CaseId or view name not specified" ); + QString error( "exportVisibleCells: CaseId or view name or view id not specified" ); RiaLogging::error( error ); return RicfCommandResponse( RicfCommandResponse::COMMAND_ERROR, error ); } - - auto eclipseView = RicfApplicationTools::viewFromCaseIdAndViewName( m_caseId, m_viewName ); + RimEclipseView* eclipseView = nullptr; + if ( m_viewId() >= 0 ) + { + eclipseView = RicfApplicationTools::viewFromCaseIdAndViewId( m_caseId, m_viewId() ); + } + else + { + eclipseView = RicfApplicationTools::viewFromCaseIdAndViewName( m_caseId, m_viewName ); + } if ( !eclipseView ) { - QString error( - QString( "exportVisibleCells: Could not find view '%1' in case ID %2" ).arg( m_viewName ).arg( m_caseId ) ); + 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 ); return RicfCommandResponse( RicfCommandResponse::COMMAND_ERROR, error ); } diff --git a/ApplicationCode/CommandFileInterface/RicfExportVisibleCells.h b/ApplicationCode/CommandFileInterface/RicfExportVisibleCells.h index e2d43c9c65..21f6973794 100644 --- a/ApplicationCode/CommandFileInterface/RicfExportVisibleCells.h +++ b/ApplicationCode/CommandFileInterface/RicfExportVisibleCells.h @@ -51,6 +51,7 @@ private: void buildExportSettings( const QString& exportFolder, RicSaveEclipseInputVisibleCellsUi* exportSettings ); caf::PdmField m_caseId; + caf::PdmField m_viewId; caf::PdmField m_viewName; caf::PdmField> m_exportKeyword; caf::PdmField m_visibleActiveCellsValue; diff --git a/ApplicationCode/CommandFileInterface/RicfSetTimeStep.cpp b/ApplicationCode/CommandFileInterface/RicfSetTimeStep.cpp index 07c5d133b6..f8f5ce87ba 100644 --- a/ApplicationCode/CommandFileInterface/RicfSetTimeStep.cpp +++ b/ApplicationCode/CommandFileInterface/RicfSetTimeStep.cpp @@ -35,6 +35,7 @@ CAF_PDM_SOURCE_INIT( RicfSetTimeStep, "setTimeStep" ); RicfSetTimeStep::RicfSetTimeStep() { RICF_InitField( &m_caseId, "caseId", -1, "Case ID", "", "", "" ); + RICF_InitField( &m_viewId, "viewId", -1, "View ID", "", "", "" ); RICF_InitField( &m_timeStepIndex, "timeStep", -1, "Time Step Index", "", "", "" ); } @@ -46,6 +47,14 @@ void RicfSetTimeStep::setCaseId( int caseId ) m_caseId = caseId; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicfSetTimeStep::setViewId( int viewId ) +{ + m_viewId = viewId; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -93,8 +102,11 @@ RicfCommandResponse RicfSetTimeStep::execute() for ( Rim3dView* view : eclipseCase->views() ) { - view->setCurrentTimeStepAndUpdate( m_timeStepIndex ); - view->createDisplayModelAndRedraw(); + if ( m_viewId() == -1 || view->id() == m_viewId() ) + { + view->setCurrentTimeStepAndUpdate( m_timeStepIndex ); + view->createDisplayModelAndRedraw(); + } } return RicfCommandResponse(); diff --git a/ApplicationCode/CommandFileInterface/RicfSetTimeStep.h b/ApplicationCode/CommandFileInterface/RicfSetTimeStep.h index 3ffaef6c51..0933f62ce6 100644 --- a/ApplicationCode/CommandFileInterface/RicfSetTimeStep.h +++ b/ApplicationCode/CommandFileInterface/RicfSetTimeStep.h @@ -35,11 +35,13 @@ public: RicfSetTimeStep(); void setCaseId( int caseId ); + void setViewId( int viewId ); void setTimeStepIndex( int timeStepIndex ); RicfCommandResponse execute() override; private: caf::PdmField m_caseId; + caf::PdmField m_viewId; caf::PdmField m_timeStepIndex; }; diff --git a/ApplicationCode/Commands/ExportCommands/RicSnapshotAllViewsToFileFeature.cpp b/ApplicationCode/Commands/ExportCommands/RicSnapshotAllViewsToFileFeature.cpp index 5839e75329..84b39f65cf 100644 --- a/ApplicationCode/Commands/ExportCommands/RicSnapshotAllViewsToFileFeature.cpp +++ b/ApplicationCode/Commands/ExportCommands/RicSnapshotAllViewsToFileFeature.cpp @@ -60,18 +60,19 @@ void RicSnapshotAllViewsToFileFeature::saveAllViews() // Save images in snapshot catalog relative to project directory QString snapshotFolderName = app->createAbsolutePathFromProjectRelativePath( "snapshots" ); - exportSnapshotOfAllViewsIntoFolder( snapshotFolderName ); + exportSnapshotOfViewsIntoFolder( snapshotFolderName ); QString text = QString( "Exported snapshots to folder : \n%1" ).arg( snapshotFolderName ); RiaLogging::info( text ); } //-------------------------------------------------------------------------------------------------- -/// Export all snapshots of a given case (or caseId == -1 for all cases) +/// Export snapshots of a given view (or viewId == -1 for all views) for the given case (or caseId == -1 for all cases) //-------------------------------------------------------------------------------------------------- -void RicSnapshotAllViewsToFileFeature::exportSnapshotOfAllViewsIntoFolder( const QString& snapshotFolderName, - const QString& prefix /*= ""*/, - int caseId /*= -1*/ ) +void RicSnapshotAllViewsToFileFeature::exportSnapshotOfViewsIntoFolder( const QString& snapshotFolderName, + const QString& prefix /*= ""*/, + int caseId /*= -1*/, + int viewId /*= -1*/ ) { RimProject* project = RiaApplication::instance()->project(); @@ -104,7 +105,7 @@ void RicSnapshotAllViewsToFileFeature::exportSnapshotOfAllViewsIntoFolder( const { Rim3dView* riv = views[j]; - if ( riv && riv->viewer() ) + if ( riv && riv->viewer() && ( viewId == -1 || viewId == riv->id() ) ) { RiaApplication::instance()->setActiveReservoirView( riv ); diff --git a/ApplicationCode/Commands/ExportCommands/RicSnapshotAllViewsToFileFeature.h b/ApplicationCode/Commands/ExportCommands/RicSnapshotAllViewsToFileFeature.h index 950b08079c..1a2b9e8a21 100644 --- a/ApplicationCode/Commands/ExportCommands/RicSnapshotAllViewsToFileFeature.h +++ b/ApplicationCode/Commands/ExportCommands/RicSnapshotAllViewsToFileFeature.h @@ -32,9 +32,10 @@ class RicSnapshotAllViewsToFileFeature : public caf::CmdFeature public: static void saveAllViews(); - static void exportSnapshotOfAllViewsIntoFolder( const QString& snapshotFolderName, - const QString& prefix = "", - int caseId = -1 ); + static void exportSnapshotOfViewsIntoFolder( const QString& snapshotFolderName, + const QString& prefix = "", + int caseId = -1, + int viewId = -1 ); protected: // Overrides diff --git a/ApplicationCode/GrpcInterface/CMakeLists.cmake b/ApplicationCode/GrpcInterface/CMakeLists.cmake index 6271a0ad20..bbe88eca91 100644 --- a/ApplicationCode/GrpcInterface/CMakeLists.cmake +++ b/ApplicationCode/GrpcInterface/CMakeLists.cmake @@ -85,7 +85,7 @@ set(PROTO_FILES "Commands" "App" "Properties" - "Grid" + "grid" ) set(GRPC_PYTHON_SOURCE_PATH "${CMAKE_CURRENT_LIST_DIR}/Python") @@ -162,15 +162,13 @@ if (RESINSIGHT_GRPC_PYTHON_EXECUTABLE) list(APPEND GRPC_PYTHON_SOURCES "rips/generated/RiaVersionInfo.py" "rips/__init__.py" - "rips/Case.py" - "rips/Commands.py" - "rips/Grid.py" - "rips/GridCaseGroup.py" - "rips/Project.py" - "rips/Properties.py" - "rips/Instance.py" - "rips/PdmObject.py" - "rips/View.py" + "rips/case.py" + "rips/grid.py" + "rips/gridcasegroup.py" + "rips/project.py" + "rips/instance.py" + "rips/pdmobject.py" + "rips/view.py" "rips/PythonExamples/InstanceExample.py" "rips/PythonExamples/CommandExample.py" "rips/PythonExamples/CaseGridGroup.py" @@ -191,7 +189,6 @@ if (RESINSIGHT_GRPC_PYTHON_EXECUTABLE) "rips/PythonExamples/SoilAverageSync.py" "rips/PythonExamples/ViewExample.py" "rips/tests/test_cases.py" - "rips/tests/test_commands.py" "rips/tests/test_grids.py" "rips/tests/test_properties.py" "rips/tests/test_project.py" diff --git a/ApplicationCode/GrpcInterface/GrpcProtos/Commands.proto b/ApplicationCode/GrpcInterface/GrpcProtos/Commands.proto index 8676996ecf..7c3506bd38 100644 --- a/ApplicationCode/GrpcInterface/GrpcProtos/Commands.proto +++ b/ApplicationCode/GrpcInterface/GrpcProtos/Commands.proto @@ -53,6 +53,7 @@ message ExportSnapshotsRequest SnapshotType type = 1; string prefix = 2; int32 caseId = 3; + int32 viewId = 4; } message ExportPropertyRequest @@ -67,9 +68,9 @@ message ExportPropertyRequest message ExportPropertyInViewsRequest { - int32 caseId = 1; - repeated string viewNames = 2; - double undefinedValue = 3; + int32 caseId = 1; + repeated int32 viewIds = 2; + double undefinedValue = 3; } enum CompdatExportSplit @@ -89,7 +90,7 @@ enum CompdatExportType enum CompdatCombinationMode { INDIVIDUALLY = 0; - caCOMBINED = 1; + COMBINED = 1; } message ExportWellPathCompRequest @@ -108,7 +109,7 @@ message ExportWellPathCompRequest message ExportSimWellPathFracRequest { int32 caseId = 1; - string viewName = 2; + int32 viewId = 2; int32 timeStep = 3; repeated string simulationWellNames = 4; CompdatExportSplit fileSplit = 5; @@ -130,7 +131,7 @@ message ExportWellPathRequest message ExportVisibleCellsRequest { int32 caseId = 1; - string viewName = 2; + int32 viewId = 2; string exportKeyword = 3; int32 visibleActiveCellsValue = 4; int32 hiddenActiveCellsValue = 5; @@ -175,7 +176,8 @@ message ComputeCaseGroupStatRequest message SetTimeStepParams { int32 caseId = 1; - int32 timeStep = 2; + int32 viewId = 2; + int32 timeStep = 3; } message ScaleFractureTemplateRequest diff --git a/ApplicationCode/GrpcInterface/Python/rips/Case.py b/ApplicationCode/GrpcInterface/Python/rips/Case.py deleted file mode 100644 index 1722a7e614..0000000000 --- a/ApplicationCode/GrpcInterface/Python/rips/Case.py +++ /dev/null @@ -1,188 +0,0 @@ -import grpc -import os -import sys -from rips.Commands import Commands -from rips.Grid import Grid -from rips.Properties import Properties -from rips.PdmObject import PdmObject -from rips.View import View - -sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'generated')) - -import Case_pb2 -import Case_pb2_grpc -import PdmObject_pb2 - -class Case (PdmObject): - """ResInsight case class - - Operate on a ResInsight case specified by a Case Id integer. - Not meant to be constructed separately but created by one of the following - methods in Project: loadCase, case, allCases, selectedCases - - Attributes: - id (int): Case Id corresponding to case Id in ResInsight project. - name (str): Case name - groupId (int): Case Group id - """ - def __init__(self, channel, id): - self.channel = channel - self.stub = Case_pb2_grpc.CaseStub(channel) - self.id = id - info = self.stub.GetCaseInfo(Case_pb2.CaseRequest(id=self.id)) - self.name = info.name - self.group_id = info.group_id - self.type = info.type - self.properties = Properties(self) - self.request = Case_pb2.CaseRequest(id=self.id) - PdmObject.__init__(self, self.stub.GetPdmObject(self.request), self.channel) - - def grid_count(self): - """Get number of grids in the case""" - try: - return self.stub.GetGridCount(self.request).count - except grpc.RpcError as e: - if e.code() == grpc.StatusCode.NOT_FOUND: - return 0 - print("ERROR: ", e) - return 0 - - def grid_path(self): - return self.get_value("CaseFileName") - - def grid(self, index): - """Get Grid of a given index. Returns a rips Grid object - - Arguments: - index (int): The grid index - - Returns: Grid object - """ - return Grid(index, self) - - def grids(self): - """Get a list of all rips Grid objects in the case""" - grid_list = [] - for i in range(0, self.grid_count()): - grid_list.append(Grid(i, self)) - return grid_list - - def cell_count(self, porosity_model='MATRIX_MODEL'): - """Get a cell count object containing number of active cells and - total number of cells - - Arguments: - porosity_model (str): String representing an enum. - must be 'MATRIX_MODEL' or 'FRACTURE_MODEL'. - Returns: - Cell Count object with the following integer attributes: - active_cell_count: number of active cells - reservoir_cell_count: total number of reservoir cells - """ - porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model) - request = Case_pb2.CellInfoRequest(case_request=self.request, - porosity_model=porosity_model_enum) - return self.stub.GetCellCount(request) - - def cell_info_for_active_cells_async(self, porosity_model='MATRIX_MODEL'): - """Get Stream of cell info objects for current case - - Arguments: - porosity_model(str): String representing an enum. - must be 'MATRIX_MODEL' or 'FRACTURE_MODEL'. - - Returns: - Stream of **CellInfo** objects - - See cell_info_for_active_cells() for detalis on the **CellInfo** class. - """ - porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model) - request = Case_pb2.CellInfoRequest(case_request=self.request, - porosity_model=porosity_model_enum) - return self.stub.GetCellInfoForActiveCells(request) - - def cell_info_for_active_cells(self, porosity_model='MATRIX_MODEL'): - """Get list of cell info objects for current case - - Arguments: - porosity_model(str): String representing an enum. - must be 'MATRIX_MODEL' or 'FRACTURE_MODEL'. - - Returns: - List of **CellInfo** objects - - ### CellInfo class description - - Parameter | Description | Type - ------------------------- | --------------------------------------------- | ----- - grid_index | Index to grid | Integer - parent_grid_index | Index to parent grid | Integer - coarsening_box_index | Index to coarsening box | Integer - local_ijk | Cell index in IJK directions of local grid | Vec3i - parent_ijk | Cell index in IJK directions of parent grid | Vec3i - - ### Vec3i class description - - Parameter | Description | Type - ---------------- | -------------------------------------------- | ----- - i | I grid index | Integer - j | J grid index | Integer - k | K grid index | Integer - - """ - active_cell_info_chunks = self.cell_info_for_active_cells_async() - received_active_cells = [] - for active_cell_chunk in active_cell_info_chunks: - for active_cell in active_cell_chunk.data: - received_active_cells.append(active_cell) - return received_active_cells - - def time_steps(self): - """Get a list containing all time steps - - The time steps are defined by the class **TimeStepDate** : - - Type | Name - --------- | ---------- - int | year - int | month - int | day - int | hour - int | minute - int | second - - - """ - return self.stub.GetTimeSteps(self.request).dates - - def days_since_start(self): - """Get a list of decimal values representing days since the start of the simulation""" - return self.stub.GetDaysSinceStart(self.request).day_decimals - - def views(self): - """Get a list of views belonging to a case""" - pdm_objects = self.children("ReservoirViews") - view_list = [] - for pdm_object in pdm_objects: - view_list.append(View(pdm_object)) - return view_list - - def view(self, id): - """Get a particular view belonging to a case by providing view id - Arguments: - id(int): view id - - Returns: a view object - - """ - views = self.views() - for view_object in views: - if view_object.id == id: - return view_object - return None - - def create_view(self): - """Create a new view in the current case""" - view_id = Commands(self.channel).create_view(self.id) - return self.view(view_id) - diff --git a/ApplicationCode/GrpcInterface/Python/rips/Commands.py b/ApplicationCode/GrpcInterface/Python/rips/Commands.py deleted file mode 100644 index f7956ded4e..0000000000 --- a/ApplicationCode/GrpcInterface/Python/rips/Commands.py +++ /dev/null @@ -1,311 +0,0 @@ -import grpc -import os -import sys - -sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'generated')) - -from Definitions_pb2 import Empty -import Commands_pb2 as Cmd -import Commands_pb2_grpc as CmdRpc -import rips.Case - -class Commands: - """Command executor which can run ResInsight Command File commands nearly verbatim. See - [ Command File Interface ]({{< ref "commandfile.md" >}}) - - The differences are: - - - Enum values have to be provided as strings. I.e. "ALL" instead of ALL. - - Booleans have to be specified as correct Python. True instead of true. - - """ - def __init__(self, channel): - self.channel = channel - self.commands = CmdRpc.CommandsStub(channel) - - def __execute(self, **command_params): - return self.commands.Execute(Cmd.CommandParams(**command_params)) - - ######################## - # Case Control Commands - ######################## - - def open_project(self, path): - """Open a project - - Arguments: - path (str): path to project file - - - """ - return self.__execute(openProject=Cmd.FilePathRequest(path=path)) - - def close_project(self): - """Close the current project (and reopen empty one)""" - return self.__execute(closeProject=Empty()) - - def set_start_dir(self, path): - """Set current start directory - - Arguments: - path (str): path to directory - - """ - return self.__execute(setStartDir=Cmd.FilePathRequest(path=path)) - - def load_case(self, path): - """Load a case - - Arguments: - path (str): path to EGRID file - - Returns: - A Case object - - """ - command_reply = self.__execute(loadCase=Cmd.FilePathRequest(path=path)) - return rips.Case(self.channel, command_reply.loadCaseResult.id) - - def replace_case(self, new_grid_file, case_id=0): - """Replace the given case with a new case loaded from file - - Arguments: - new_grid_file (str): path to EGRID file - case_id (int): case Id to replace - - """ - return self.__execute(replaceCase=Cmd.ReplaceCaseRequest(newGridFile=new_grid_file, - caseId=case_id)) - - def replace_source_cases(self, grid_list_file, case_group_id=0): - """Replace all source cases within a case group - - Arguments: - grid_list_file (str): path to file containing a list of cases - case_group_id (int): id of the case group to replace - - """ - return self.__execute(replaceSourceCases=Cmd.ReplaceSourceCasesRequest(gridListFile=grid_list_file, - caseGroupId=case_group_id)) - - def create_grid_case_group(self, case_paths): - """Create a Grid Case Group from a list of cases - - Arguments: - case_paths (list): list of file path strings - - Returns: - A case group id and name - """ - commandReply = self.__execute(createGridCaseGroup=Cmd.CreateGridCaseGroupRequest(casePaths=case_paths)) - return (commandReply.createGridCaseGroupResult.groupId, commandReply.createGridCaseGroupResult.groupName) - - def create_statistics_case(self, case_group_id): - """Create a Statistics case in a Grid Case Group - - Arguments: - case_group_id (int): id of the case group - - Returns: - A case id for the new case - """ - commandReply = self.__execute(createStatisticsCase=Cmd.CreateStatisticsCaseRequest(caseGroupId=case_group_id)) - return commandReply.createStatisticsCaseResult.caseId - - ################## - # Export Commands - ################## - - def export_multi_case_snapshots(self, grid_list_file): - """Export snapshots for a set of cases - - Arguments: - grid_list_file (str): Path to a file containing a list of grids to export snapshot for - - """ - return self.__execute(exportMultiCaseSnapshot=Cmd.ExportMultiCaseRequest(gridListFile=grid_list_file)) - - def export_snapshots(self, type = 'ALL', prefix='', case_id = -1): - """ Export snapshots of a given type - - Arguments: - type (str): Enum string ('ALL', 'VIEWS' or 'PLOTS') - prefix (str): Exported file name prefix - case_id (int): the case Id to export for. The default of -1 will export all cases - - """ - return self.__execute(exportSnapshots=Cmd.ExportSnapshotsRequest(type=type, - prefix=prefix, - caseId=case_id)) - - def export_property(self, case_id, time_step, property, eclipse_keyword=property, undefined_value=0.0, export_file=property): - """ Export an Eclipse property - - Arguments: - case_id (int): case id - time_step (int): time step index - property (str): property to export - eclipse_keyword (str): Eclipse keyword used as text in export header. Defaults to the value of property parameter. - undefined_value (double): Value to use for undefined values. Defaults to 0.0 - export_file (str): File name for export. Defaults to the value of property parameter - """ - return self.__execute(exportProperty=Cmd.ExportPropertyRequest(caseId=case_id, - timeStep=time_step, - property=property, - eclipseKeyword=eclipse_keyword, - undefinedValue=undefined_value, - exportFile=export_file)) - - def export_property_in_views(self, case_id, view_names, undefined_value): - """ Export the current Eclipse property from the given views - - Arguments: - case_id (int): case id - view_names (list): list of views - undefined_value (double): Value to use for undefined values. Defaults to 0.0 - """ - if isinstance(view_names, str): - view_names = [view_names] - - return self.__execute(exportPropertyInViews=Cmd.ExportPropertyInViewsRequest(caseId=case_id, - viewNames=view_names, - undefinedValue=undefined_value)) - - def export_well_path_completions(self, case_id, time_step, well_path_names, file_split, - compdat_export, include_perforations, include_fishbones, - exclude_main_bore_for_fishbones, combination_mode): - if (isinstance(well_path_names, str)): - well_path_names = [well_path_names] - return self.__execute(exportWellPathCompletions=Cmd.ExportWellPathCompRequest(caseId=case_id, - timeStep=time_step, - wellPathNames=well_path_names, - fileSplit=file_split, - compdatExport=compdat_export, - includePerforations=include_perforations, - includeFishbones=include_fishbones, - excludeMainBoreForFishbones=exclude_main_bore_for_fishbones, - combinationMode=combination_mode)) - - def export_sim_well_fracture_completions(self, case_id, view_name, time_step, simulation_well_names, file_split, compdat_export): - if(isinstance(simulation_well_names, str)): - simulation_well_names = [simulation_well_names] - return self.__execute(exportSimWellFractureCompletions=Cmd.ExportSimWellPathFraqRequest(caseId=case_id, - viewName=view_name, - timeStep=time_step, - simulationWellNames=simulation_well_names, - fileSplit=file_split, - compdatExport=compdat_export)) - - def export_msw(self, case_id, well_path): - return self.__execute(exportMsw=Cmd.ExportMswRequest(caseId=case_id, - wellPath=well_path)) - - def export_well_paths(self, well_paths=[], md_step_size=5.0): - if isinstance(well_paths, str): - well_paths = [well_paths] - return self.__execute(exportWellPaths=Cmd.ExportWellPathRequest(wellPathNames=well_paths, mdStepSize=md_step_size)) - - def export_visible_cells(self, case_id, view_name, export_keyword='FLUXNUM', visible_active_cells_value=1, hidden_active_cells_value=0, inactive_cells_value=0): - return self.__execute(exportVisibleCells=Cmd.ExportVisibleCellsRequest(caseId=case_id, - viewName=view_name, - exportKeyword=export_keyword, - visibleActiveCellsValue=visible_active_cells_value, - hiddenActiveCellsValue=hidden_active_cells_value, - inactiveCellsValue=inactive_cells_value)) - def set_export_folder(self, type, path, create_folder=False): - return self.__execute(setExportFolder=Cmd.SetExportFolderRequest(type=type, - path=path, - createFolder=create_folder)) - - def run_octave_script(self, path, cases): - caseIds = [] - for case in cases: - caseIds.append(case.id) - return self.__execute(runOctaveScript=Cmd.RunOctaveScriptRequest(path=path, - caseIds=caseIds)) - - def set_main_window_size(self, width, height): - return self.__execute(setMainWindowSize=Cmd.SetMainWindowSizeParams(width=width, height=height)) - - def compute_case_group_statistics(self, case_ids = [], case_group_id = -1): - return self.__execute(computeCaseGroupStatistics=Cmd.ComputeCaseGroupStatRequest(caseIds=case_ids, - caseGroupId=case_group_id)) - - def set_time_step(self, case_id, time_step): - return self.__execute(setTimeStep=Cmd.SetTimeStepParams(caseId=case_id, timeStep=time_step)) - - def scale_fracture_template(self, id, half_length, height, dfactor, conductivity): - return self.__execute(scaleFractureTemplate=Cmd.ScaleFractureTemplateRequest(id=id, - halfLength=half_length, - height=height, - dFactor=dfactor, - conductivity=conductivity)) - - def set_fracture_containment(self, id, top_layer, base_layer): - return self.__execute(setFractureContainment=Cmd.SetFracContainmentRequest(id=id, - topLayer=top_layer, - baseLayer=base_layer)) - - def create_multiple_fractures(self, case_id, template_id, well_path_names, min_dist_from_well_td, - max_fractures_per_well, top_layer, base_layer, spacing, action): - if isinstance(well_path_names, str): - well_path_names = [well_path_names] - return self.__execute(createMultipleFractures=Cmd.MultipleFracAction(caseId=case_id, - templateId=template_id, - wellPathNames=well_path_names, - minDistFromWellTd=min_dist_from_well_td, - maxFracturesPerWell=max_fractures_per_well, - topLayer=top_layer, - baseLayer=base_layer, - spacing=spacing, - action=action)) - - def create_lgr_for_completion(self, case_id, time_step, well_path_names, refinement_i, refinement_j, refinement_k, split_type): - if isinstance(well_path_names, str): - well_path_names = [well_path_names] - return self.__execute(createLgrForCompletions=Cmd.CreateLgrForCompRequest(caseId=case_id, - timeStep=time_step, - wellPathNames=well_path_names, - refinementI=refinement_i, - refinementJ=refinement_j, - refinementK=refinement_k, - splitType=split_type)) - - def create_saturation_pressure_plots(self, case_ids): - if isinstance(case_ids, int): - case_ids = [case_ids] - return self.__execute(createSaturationPressurePlots=Cmd.CreateSatPressPlotRequest(caseIds=case_ids)) - - def export_flow_characteristics(self, case_id, time_steps, injectors, producers, file_name, minimum_communication=0.0, aquifer_cell_threshold=0.1): - """ Export Flow Characteristics data to text file in CSV format - - Parameter | Description | Type - ------------------------- | --------------------------------------------- | ----- - case_id | ID of case | Integer - time_steps | Time step indices | List of Integer - injectors | Injector names | List of Strings - producers | Producer names | List of Strings - file_name | Export file name | Integer - minimum_communication | Minimum Communication, defaults to 0.0 | Integer - aquifer_cell_threshold | Aquifer Cell Threshold, defaults to 0.1 | Integer - - """ - if isinstance(time_steps, int): - time_steps = [time_steps] - if isinstance(injectors, str): - injectors = [injectors] - if isinstance(producers, str): - producers = [producers] - return self.__execute(exportFlowCharacteristics=Cmd.ExportFlowInfoRequest(caseId=case_id, - timeSteps=time_steps, - injectors=injectors, - producers=producers, - fileName=file_name, - minimumCommunication = minimum_communication, - aquiferCellThreshold = aquifer_cell_threshold)) - - def create_view(self, case_id): - return self.__execute(createView=Cmd.CreateViewRequest(caseId=case_id)).createViewResult.viewId - - def clone_view(self, view_id): - return self.__execute(cloneView=Cmd.CloneViewRequest(viewId=view_id)).createViewResult.viewId \ No newline at end of file diff --git a/ApplicationCode/GrpcInterface/Python/rips/Grid.py b/ApplicationCode/GrpcInterface/Python/rips/Grid.py deleted file mode 100644 index 3a8ab8d77f..0000000000 --- a/ApplicationCode/GrpcInterface/Python/rips/Grid.py +++ /dev/null @@ -1,27 +0,0 @@ -import grpc -import os -import sys - -sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'generated')) - -import Grid_pb2 -import Grid_pb2_grpc - -class Grid: - """Grid Information. Not meant to be constructed separately - - Create Grid objects using mathods on Case: Grid() and Grids() - """ - def __init__(self, index, case): - self.case = case - self.index = index - self.stub = Grid_pb2_grpc.GridStub(self.case.channel) - - def dimensions(self): - """The dimensions in i, j, k direction - - Returns: - Vec3i: class with integer attributes i, j, k representing the extent in all three dimensions. - """ - return self.stub.GetDimensions(Grid_pb2.GridRequest(case_request = self.case.request, grid_index = self.index)).dimensions - diff --git a/ApplicationCode/GrpcInterface/Python/rips/GridCaseGroup.py b/ApplicationCode/GrpcInterface/Python/rips/GridCaseGroup.py deleted file mode 100644 index 499e53f0e7..0000000000 --- a/ApplicationCode/GrpcInterface/Python/rips/GridCaseGroup.py +++ /dev/null @@ -1,48 +0,0 @@ -import grpc -import os -import sys -from rips.PdmObject import PdmObject -from rips.View import View - -sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'generated')) - -import PdmObject_pb2 - -class GridCaseGroup (PdmObject): - """ResInsight Grid Case Group class - - Operate on a ResInsight case group specified by a Case Group Id integer. - - Attributes: - group_id (int): Grid Case Group Id corresponding to case group Id in ResInsight project. - """ - def __init__(self, pdm_object): - self.group_id = pdm_object.get_value("GroupId") - PdmObject.__init__(self, pdm_object.pb2Object, pdm_object.channel) - - def statistics_cases(self): - """Get a list of all statistics cases in the Grid Case Group""" - stat_case_collection = self.children("StatisticsCaseCollection")[0] - return stat_case_collection.children("Reservoirs") - - def views(self): - """Get a list of views belonging to a grid case group""" - pdm_objects = self.descendants("ReservoirView") - view_list = [] - for pdm_object in pdm_objects: - view_list.append(View(pdm_object)) - return view_list - - def view(self, id): - """Get a particular view belonging to a case group by providing view id - Arguments: - id(int): view id - - Returns: a view object - - """ - views = self.views() - for view_object in views: - if view_object.id == id: - return view_object - return None diff --git a/ApplicationCode/GrpcInterface/Python/rips/Instance.py b/ApplicationCode/GrpcInterface/Python/rips/Instance.py deleted file mode 100644 index c1902e7fae..0000000000 --- a/ApplicationCode/GrpcInterface/Python/rips/Instance.py +++ /dev/null @@ -1,196 +0,0 @@ -import grpc -import os -import sys -import socket -import logging -import time - -sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'generated')) -import App_pb2 -import App_pb2_grpc -from Definitions_pb2 import Empty - -import RiaVersionInfo - -from rips.Commands import Commands -from rips.Project import Project - -class Instance: - """The ResInsight Instance class. Use to launch or find existing ResInsight instances - - Attributes: - launched (bool): Tells us whether the application was launched as a new process. - If the application was launched we may need to close it when exiting the script. - commands (Commands): Command executor. Set when creating an instance. - project (Project): Current project in ResInsight. - Set when creating an instance and updated when opening/closing projects. - """ - - @staticmethod - def __is_port_in_use(port): - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - s.settimeout(0.2) - return s.connect_ex(('localhost', port)) == 0 - - @staticmethod - def launch(resinsight_executable = '', console = False, launch_port = -1, command_line_parameters=[]): - """ Launch a new Instance of ResInsight. This requires the environment variable - RESINSIGHT_EXECUTABLE to be set or the parameter resinsight_executable to be provided. - The RESINSIGHT_GRPC_PORT environment variable can be set to an alternative port number. - - Args: - resinsight_executable (str): Path to a valid ResInsight executable. If set - will take precedence over what is provided in the RESINSIGHT_EXECUTABLE - environment variable. - console (bool): If True, launch as console application, without GUI. - launch_port(int): If -1 will use the default port of 50051 or look for RESINSIGHT_GRPC_PORT - if anything else, ResInsight will try to launch with this port - command_line_parameters(list): Additional command line parameters as string entries in the list. - Returns: - Instance: an instance object if it worked. None if not. - """ - - port = 50051 - port_env = os.environ.get('RESINSIGHT_GRPC_PORT') - if port_env: - port = int(port_env) - if launch_port is not -1: - port = launch_port - - if not resinsight_executable: - resinsight_executable = os.environ.get('RESINSIGHT_EXECUTABLE') - if not resinsight_executable: - print('ERROR: Could not launch ResInsight because the environment variable' - ' RESINSIGHT_EXECUTABLE is not set') - return None - - while Instance.__is_port_in_use(port): - port += 1 - - print('Port ' + str(port)) - print('Trying to launch', resinsight_executable) - - if isinstance(command_line_parameters, str): - command_line_parameters = [str] - - parameters = ["ResInsight", "--server", str(port)] + command_line_parameters - if console: - print("Launching as console app") - parameters.append("--console") - - # Stringify all parameters - for i in range(0, len(parameters)): - parameters[i] = str(parameters[i]) - - pid = os.spawnv(os.P_NOWAIT, resinsight_executable, parameters) - if pid: - instance = Instance(port=port, launched=True) - return instance - return None - - @staticmethod - def find(start_port = 50051, end_port = 50071): - """ Search for an existing Instance of ResInsight by testing ports. - - By default we search from port 50051 to 50071 or if the environment - variable RESINSIGHT_GRPC_PORT is set we search - RESINSIGHT_GRPC_PORT to RESINSIGHT_GRPC_PORT+20 - - Args: - start_port (int): start searching from this port - end_port (int): search up to but not including this port - """ - port_env = os.environ.get('RESINSIGHT_GRPC_PORT') - if port_env: - start_port = int(port_env) - end_port = start_port + 20 - - for try_port in range(start_port, end_port): - if Instance.__is_port_in_use(try_port): - return Instance(port=try_port) - - print('Error: Could not find any ResInsight instances responding between ports ' + str(start_port) + ' and ' + str(end_port)) - return None - - def __check_version(self): - try: - major_version_ok = self.major_version() == int(RiaVersionInfo.RESINSIGHT_MAJOR_VERSION) - minor_version_ok = self.minor_version() == int(RiaVersionInfo.RESINSIGHT_MINOR_VERSION) - return True, major_version_ok and minor_version_ok - except: - return False, False - - def __init__(self, port = 50051, launched = False): - """ Attempts to connect to ResInsight at aa specific port on localhost - - Args: - port(int): port number - """ - logging.basicConfig() - location = "localhost:" + str(port) - - self.channel = grpc.insecure_channel(location, options=[('grpc.enable_http_proxy', False)]) - self.launched = launched - - # Main version check package - self.app = self.app = App_pb2_grpc.AppStub(self.channel) - - connection_ok = False - version_ok = False - - if self.launched: - for i in range(0, 10): - connection_ok, version_ok = self.__check_version() - if connection_ok: - break - time.sleep(1.0) - else: - connection_ok, version_ok = self.__check_version() - - if not connection_ok: - if self.launched: - raise Exception('Error: Could not connect to resinsight at ', location, ' after trying 10 times with 1 second apart') - else: - raise Exception('Error: Could not connect to resinsight at ', location) - exit(1) - if not version_ok: - raise Exception('Error: Wrong Version of ResInsight at ', location) - - # Service packages - self.commands = Commands(self.channel) - self.project = Project(self.channel) - - path = os.getcwd() - self.commands.set_start_dir(path=path) - - def __version_message(self): - return self.app.GetVersion(Empty()) - - def major_version(self): - """Get an integer with the major version number""" - return self.__version_message().major_version - - def minor_version(self): - """Get an integer with the minor version number""" - return self.__version_message().minor_version - - def patch_version(self): - """Get an integer with the patch version number""" - return self.__version_message().patch_version - - def version_string(self): - """Get a full version string, i.e. 2019.04.01""" - return str(self.major_version()) + "." + str(self.minor_version()) + "." + str(self.patch_version()) - - def exit(self): - """Tell ResInsight instance to quit""" - print("Telling ResInsight to Exit") - return self.app.Exit(Empty()) - - def is_console(self): - """Returns true if the connected ResInsight instance is a console app""" - return self.app.GetRuntimeInfo(Empty()).app_type == App_pb2.ApplicationTypeEnum.Value('CONSOLE_APPLICATION') - - def is_gui(self): - """Returns true if the connected ResInsight instance is a GUI app""" - return self.app.GetRuntimeInfo(Empty()).app_type == App_pb2.ApplicationTypeEnum.Value('GUI_APPLICATION') diff --git a/ApplicationCode/GrpcInterface/Python/rips/Project.py b/ApplicationCode/GrpcInterface/Python/rips/Project.py deleted file mode 100644 index 3cc06935ad..0000000000 --- a/ApplicationCode/GrpcInterface/Python/rips/Project.py +++ /dev/null @@ -1,149 +0,0 @@ -import grpc -import os -import sys - -from rips.Case import Case -from rips.Commands import Commands -from rips.GridCaseGroup import GridCaseGroup -from rips.PdmObject import PdmObject -from rips.View import View - -sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'generated')) - -from Definitions_pb2 import Empty -import Project_pb2 -import Project_pb2_grpc - -class Project (PdmObject): - """ResInsight project. Not intended to be created separately. - - Automatically created and assigned to Instance. - """ - def __init__(self, channel): - self.channel = channel - self.project = Project_pb2_grpc.ProjectStub(channel) - PdmObject.__init__(self, self.project.GetPdmObject(Empty()), self.channel) - - def open(self, path): - """Open a new project from the given path - - Arguments: - path(str): path to project file - - """ - Commands(self.channel).open_project(path) - return self - - def close(self): - """Close the current project (and open new blank project)""" - Commands(self.channel).close_project() - - def selected_cases(self): - """Get a list of all cases selected in the project tree - - Returns: - A list of rips Case objects - """ - case_infos = self.project.GetSelectedCases(Empty()) - cases = [] - for case_info in case_infos.data: - cases.append(Case(self.channel, case_info.id)) - return cases - - def cases(self): - """Get a list of all cases in the project - - Returns: - A list of rips Case objects - """ - try: - case_infos = self.project.GetAllCases(Empty()) - - cases = [] - for case_info in case_infos.data: - cases.append(Case(self.channel, case_info.id)) - return cases - except grpc.RpcError as e: - if e.code() == grpc.StatusCode.NOT_FOUND: - return [] - else: - print("ERROR: ", e) - return [] - - def case(self, id): - """Get a specific case from the provided case Id - - Arguments: - id(int): case id - Returns: - A rips Case object - """ - try: - case = Case(self.channel, id) - return case - except grpc.RpcError as e: - return None - - def load_case(self, path): - """Load a new case from the given file path - - Arguments: - path(str): file path to case - Returns: - A rips Case object - """ - return Commands(self.channel).load_case(path) - - def views(self): - """Get a list of views belonging to a project""" - pdm_objects = self.descendants("ReservoirView") - view_list = [] - for pdm_object in pdm_objects: - view_list.append(View(pdm_object)) - return view_list - - def view(self, id): - """Get a particular view belonging to a case by providing view id - Arguments: - id(int): view id - - Returns: a view object - - """ - views = self.views() - for view_object in views: - if view_object.id == id: - return view_object - return None - - def grid_case_groups(self): - """Get a list of all grid case groups in the project""" - case_groups = self.descendants("RimIdenticalGridCaseGroup") - - case_group_list = [] - for pdm_group in case_groups: - case_group_list.append(GridCaseGroup(pdm_group)) - return case_group_list - - def grid_case_group(self, group_id): - """Get a particular grid case group belonging to a project - Arguments: - groupId(int): group id - - Returns: a grid case group object - """ - case_groups = self.grid_case_groups() - for case_group in case_groups: - if case_group.groupId == group_id: - return case_group - return None - - def create_grid_case_group(self, case_paths): - """Create a new grid case group from the provided case paths - Arguments: - casePaths(list): a list of paths to the cases to be loaded and included in the group - Returns: - A new grid case group object - """ - group_id, group_name = Commands(self.channel).create_grid_case_group(case_paths) - return self.grid_case_group(group_id) \ No newline at end of file diff --git a/ApplicationCode/GrpcInterface/Python/rips/Properties.py b/ApplicationCode/GrpcInterface/Python/rips/Properties.py deleted file mode 100644 index ae448ada8b..0000000000 --- a/ApplicationCode/GrpcInterface/Python/rips/Properties.py +++ /dev/null @@ -1,239 +0,0 @@ -import grpc -import os -import sys - -sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'generated')) - -import Properties_pb2 -import Properties_pb2_grpc -import Case_pb2 -import Case_pb2_grpc -from Definitions_pb2 import ClientToServerStreamReply - -class Properties: - """ Class for streaming properties to and from ResInsight - - Attributes: - chunkSize(int): The size of each chunk during value streaming. - A good chunk size is 64KiB = 65536B. - Meaning the ideal number of doubles would be 8192. - However we need overhead space, so the default is 8160. - This leaves 256B for overhead. - """ - def __init__(self, case): - """ - Arguments: - case(Case): A rips case to handle properties for - """ - self.case = case - self._properties_stub = Properties_pb2_grpc.PropertiesStub(self.case.channel) - self.chunk_size = 8160 - - - def __generate_property_input_iterator(self, values_iterator, parameters): - chunk = Properties_pb2.PropertyInputChunk() - chunk.params.CopyFrom(parameters) - yield chunk - - for values in values_iterator: - valmsg = Properties_pb2.PropertyChunk(values = values) - chunk.values.CopyFrom(valmsg) - yield chunk - - def __generate_property_input_chunks(self, array, parameters): - - index = -1 - while index < len(array): - chunk = Properties_pb2.PropertyInputChunk() - if index is -1: - chunk.params.CopyFrom(parameters) - index += 1 - else: - actual_chunk_size = min(len(array) - index + 1, self.chunk_size) - chunk.values.CopyFrom(Properties_pb2.PropertyChunk(values = array[index:index+actual_chunk_size])) - index += actual_chunk_size - - yield chunk - # Final empty message to signal completion - chunk = Properties_pb2.PropertyInputChunk() - yield chunk - - def available(self, property_type, porosity_model = 'MATRIX_MODEL'): - """Get a list of available properties - - Arguments: - property_type (str): string corresponding to property_type enum. Can be one of the following: - - DYNAMIC_NATIVE - - STATIC_NATIVE - - SOURSIMRL - - GENERATED - - INPUT_PROPERTY - - FORMATION_NAMES - - FLOW_DIAGNOSTICS - - INJECTION_FLOODING - - porosity_model(str): 'MATRIX_MODEL' or 'FRACTURE_MODEL'. - """ - - property_type_enum = Properties_pb2.PropertyType.Value(property_type) - porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model) - request = Properties_pb2.AvailablePropertiesRequest (case_request = Case_pb2.CaseRequest(id=self.case.id), - property_type = property_type_enum, - porosity_model = porosity_model_enum) - return self._properties_stub.GetAvailableProperties(request).property_names - - def active_cell_property_async(self, property_type, property_name, time_step, porosity_model = 'MATRIX_MODEL'): - """Get a cell property for all active cells. Async, so returns an iterator - - Arguments: - property_type(str): string enum. See available() - property_name(str): name of an Eclipse property - time_step(int): the time step for which to get the property for - porosity_model(str): string enum. See available() - - Returns: - An iterator to a chunk object containing an array of double values - You first loop through the chunks and then the values within the chunk to get all values. - """ - property_type_enum = Properties_pb2.PropertyType.Value(property_type) - porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model) - request = Properties_pb2.PropertyRequest(case_request = Case_pb2.CaseRequest(id=self.case.id), - property_type = property_type_enum, - property_name = property_name, - time_step = time_step, - porosity_model = porosity_model_enum) - for chunk in self._properties_stub.GetActiveCellProperty(request): - yield chunk - - def active_cell_property(self, property_type, property_name, time_step, porosity_model = 'MATRIX_MODEL'): - """Get a cell property for all active cells. Sync, so returns a list - - Arguments: - property_type(str): string enum. See available() - property_name(str): name of an Eclipse property - time_step(int): the time step for which to get the property for - porosity_model(str): string enum. See available() - - Returns: - A list containing double values - You first loop through the chunks and then the values within the chunk to get all values. - """ - all_values = [] - generator = self.active_cell_property_async(property_type, property_name, time_step, porosity_model) - for chunk in generator: - for value in chunk.values: - all_values.append(value) - return all_values - - def grid_property_async(self, property_type, property_name, time_step, gridIndex = 0, porosity_model = 'MATRIX_MODEL'): - """Get a cell property for all grid cells. Async, so returns an iterator - - Arguments: - property_type(str): string enum. See available() - property_name(str): name of an Eclipse property - time_step(int): the time step for which to get the property for - gridIndex(int): index to the grid we're getting values for - porosity_model(str): string enum. See available() - - Returns: - An iterator to a chunk object containing an array of double values - You first loop through the chunks and then the values within the chunk to get all values. - """ - property_type_enum = Properties_pb2.PropertyType.Value(property_type) - porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model) - request = Properties_pb2.PropertyRequest(case_request = self.case.request, - property_type = property_type_enum, - property_name = property_name, - time_step = time_step, - grid_index = gridIndex, - porosity_model = porosity_model_enum) - for chunk in self._properties_stub.GetGridProperty(request): - yield chunk - - def grid_property(self, property_type, property_name, time_step, grid_index = 0, porosity_model = 'MATRIX_MODEL'): - """Get a cell property for all grid cells. Synchronous, so returns a list - - Arguments: - property_type(str): string enum. See available() - property_name(str): name of an Eclipse property - time_step(int): the time step for which to get the property for - grid_index(int): index to the grid we're getting values for - porosity_model(str): string enum. See available() - - Returns: - A list of double values - """ - all_values = [] - generator = self.grid_property_async(property_type, property_name, time_step, grid_index, porosity_model) - for chunk in generator: - for value in chunk.values: - all_values.append(value) - return all_values - - def set_active_cell_property_async(self, values_iterator, property_type, property_name, time_step, porosity_model = 'MATRIX_MODEL'): - """Set a cell property for all active cells. Async, and so takes an iterator to the input values - - Arguments: - values_iterator(iterator): an iterator to the properties to be set - property_type(str): string enum. See available() - property_name(str): name of an Eclipse property - time_step(int): the time step for which to get the property for - porosity_model(str): string enum. See available() - """ - property_type_enum = Properties_pb2.PropertyType.Value(property_type) - porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model) - request = Properties_pb2.PropertyRequest(case_request = self.case.request, - property_type = property_type_enum, - property_name = property_name, - time_step = time_step, - porosity_model = porosity_model_enum) - - request_iterator = self.__generate_property_input_iterator(values_iterator, request) - self._properties_stub.SetActiveCellProperty(request_iterator) - - def set_active_cell_property(self, values, property_type, property_name, time_step, porosity_model = 'MATRIX_MODEL'): - """Set a cell property for all active cells. - - Arguments: - values(list): a list of double precision floating point numbers - property_type(str): string enum. See available() - property_name(str): name of an Eclipse property - time_step(int): the time step for which to get the property for - porosity_model(str): string enum. See available() - """ - property_type_enum = Properties_pb2.PropertyType.Value(property_type) - porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model) - request = Properties_pb2.PropertyRequest(case_request = self.case.request, - property_type = property_type_enum, - property_name = property_name, - time_step = time_step, - porosity_model = porosity_model_enum) - request_iterator = self.__generate_property_input_chunks(values, request) - reply = self._properties_stub.SetActiveCellProperty(request_iterator) - if reply.accepted_value_count < len(values): - raise IndexError - - def set_grid_property(self, values, property_type, property_name, time_step, grid_index = 0, porosity_model = 'MATRIX_MODEL'): - """Set a cell property for all grid cells. - - Arguments: - values(list): a list of double precision floating point numbers - property_type(str): string enum. See available() - property_name(str): name of an Eclipse property - time_step(int): the time step for which to get the property for - grid_index(int): index to the grid we're setting values for - porosity_model(str): string enum. See available() - """ - property_type_enum = Properties_pb2.PropertyType.Value(property_type) - porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model) - request = Properties_pb2.PropertyRequest(case_request = self.case.request, - property_type = property_type_enum, - property_name = property_name, - time_step = time_step, - grid_index = grid_index, - porosity_model = porosity_model_enum) - request_iterator = self.__generate_property_input_chunks(values, request) - reply = self._properties_stub.SetGridProperty(request_iterator) - if reply.accepted_value_count < len(values): - raise IndexError - \ No newline at end of file diff --git a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/CaseGridGroup.py b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/CaseGridGroup.py index 6285e823eb..1e136c8916 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/CaseGridGroup.py +++ b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/CaseGridGroup.py @@ -6,8 +6,8 @@ resinsight = rips.Instance.find() case_paths = [] case_paths.append("C:/Users/lindk/source/repos/ResInsight/TestModels/Case_with_10_timesteps/Real0/BRUGGE_0000.EGRID") case_paths.append("C:/Users/lindk/source/repos/ResInsight/TestModels/Case_with_10_timesteps/Real10/BRUGGE_0010.EGRID") -for casePath in case_paths: - assert os.path.exists(casePath), "You need to set valid case paths for this script to work" +for case_path in case_paths: + assert os.path.exists(case_path), "You need to set valid case paths for this script to work" case_group = resinsight.project.create_grid_case_group(case_paths=case_paths) @@ -20,7 +20,7 @@ case_group.print_object_info() # stat_case.update() # case_ids.append(stat_case.get_value("CaseId")) -resinsight.commands.compute_case_group_statistics(case_group_id=case_group.group_id) +case_group.compute_statistics() view = case_group.views()[0] cell_result = view.set_cell_result() diff --git a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/CaseInfoStreamingExample.py b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/CaseInfoStreamingExample.py index 6a5ce6d880..7c839a8d14 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/CaseInfoStreamingExample.py +++ b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/CaseInfoStreamingExample.py @@ -9,7 +9,7 @@ import rips resinsight = rips.Instance.find() # Get the case with id == 0. This will fail if your project doesn't have a case with id == 0 -case = resinsight.project.case(id = 0) +case = resinsight.project.case(id=0) # Get the cell count object cell_counts = case.cell_count() diff --git a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/CommandExample.py b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/CommandExample.py index 6835ac7442..28e3839e30 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/CommandExample.py +++ b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/CommandExample.py @@ -1,7 +1,5 @@ ############################################################################### -# This example will run a few ResInsight command file commands -# .. which are exposed in the Python interface. -# Including setting time step, window size and export snapshots and properties +# This example will show setting time step, window size and export snapshots and properties ############################################################################### import os import tempfile @@ -10,9 +8,24 @@ import rips # Load instance resinsight = rips.Instance.find() -# Run a couple of commands -resinsight.commands.set_time_step(case_id=0, time_step=3) -resinsight.commands.set_main_window_size(width=800, height=500) +# Set window size +resinsight.set_main_window_size(width=800, height=500) + +# Retrieve first case +case = resinsight.project.cases()[0] + +# Get a view +view1 = case.view(view_id=0) + +# Clone the view +view2 = view1.clone() + +# Set the time step for view1 only +view1.set_time_step(time_step=2) + +# Set cell result to SOIL +view1.apply_cell_result(result_type='DYNAMIC_NATIVE', result_variable='SOIL') + # Create a temporary directory which will disappear at the end of this script # If you want to keep the files, provide a good path name instead of tmpdirname @@ -20,23 +33,23 @@ with tempfile.TemporaryDirectory(prefix="rips") as tmpdirname: print("Temporary folder: ", tmpdirname) # Set export folder for snapshots and properties - resinsight.commands.set_export_folder(type='SNAPSHOTS', path=tmpdirname) - resinsight.commands.set_export_folder(type='PROPERTIES', path=tmpdirname) - - # Export snapshots - resinsight.commands.export_snapshots() - - # Print contents of temporary folder - print(os.listdir(tmpdirname)) + resinsight.set_export_folder(export_type='SNAPSHOTS', path=tmpdirname) + resinsight.set_export_folder(export_type='PROPERTIES', path=tmpdirname) + # Export all snapshots + resinsight.project.export_snapshots() + assert(len(os.listdir(tmpdirname)) > 0) - case = resinsight.project.case(id=0) # Export properties in the view - resinsight.commands.export_property_in_views(0, "3D View", 0) - + view1.export_property() + # Check that the exported file exists - expected_file_name = case.name + "-" + str("3D_View") + "-" + "T3" + "-SOIL" + expected_file_name = case.name + "-" + str("3D_View") + "-" + "T2" + "-SOIL" full_path = tmpdirname + "/" + expected_file_name + + # Print contents of temporary folder + print(os.listdir(tmpdirname)) + assert(os.path.exists(full_path)) diff --git a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/ErrorHandling.py b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/ErrorHandling.py index d3605519f8..84866dccab 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/ErrorHandling.py +++ b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/ErrorHandling.py @@ -16,14 +16,14 @@ try: except grpc.RpcError as e: print("Expected Server Exception Received: ", e) -case = resinsight.project.case(id=0) +case = resinsight.project.case(case_id=0) if case is not None: - results = case.properties.active_cell_property('STATIC_NATIVE', 'PORO', 0) + results = case.active_cell_property('STATIC_NATIVE', 'PORO', 0) active_cell_count = len(results) # Send the results back to ResInsight inside try / except construct try: - case.properties.set_active_cell_property(results, 'GENERATED', 'POROAPPENDED', 0) + case.set_active_cell_property(results, 'GENERATED', 'POROAPPENDED', 0) print("Everything went well as expected") except: # Match any exception, but it should not happen print("Ooops!") @@ -33,7 +33,7 @@ if case is not None: # This time we should get a grpc.RpcError exception, which is a server side error. try: - case.properties.set_active_cell_property(results, 'GENERATED', 'POROAPPENDED', 0) + case.set_active_cell_property(results, 'GENERATED', 'POROAPPENDED', 0) print("Everything went well??") except grpc.RpcError as e: print("Expected Server Exception Received: ", e) @@ -43,10 +43,10 @@ if case is not None: # With a chunk size exactly matching the active cell count the server will not # be able to see any error as it will successfully close the stream after receiving # the correct number of values, even if the python client has more chunks to send - case.properties.chunk_size = active_cell_count + case.chunk_size = active_cell_count try: - case.properties.set_active_cell_property(results, 'GENERATED', 'POROAPPENDED', 0) + case.set_active_cell_property(results, 'GENERATED', 'POROAPPENDED', 0) print("Everything went well??") except grpc.RpcError as e: print("Got unexpected server exception", e, "This should not happen now") diff --git a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/ExportSnapshots.py b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/ExportSnapshots.py index 380cfcff12..c6e715f5f2 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/ExportSnapshots.py +++ b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/ExportSnapshots.py @@ -10,13 +10,15 @@ resinsight = rips.Instance.find() cases = resinsight.project.cases() # Set main window size -resinsight.commands.set_main_window_size(width=800, height=500) +resinsight.set_main_window_size(width=800, height=500) n = 5 # every n-th time_step for snapshot property_list = ['SOIL', 'PRESSURE'] # list of parameter for snapshot print ("Looping through cases") for case in cases: + print("Case name: ", case.name) + print("Case id: ", case.case_id) # Get grid path and its folder name case_path = case.grid_path() folder_name = os.path.dirname(case_path) @@ -28,16 +30,14 @@ for case in cases: os.mkdir(dirname) print ("Exporting to folder: " + dirname) - resinsight.commands.set_export_folder(type='SNAPSHOTS', path=dirname) + resinsight.set_export_folder(export_type='SNAPSHOTS', path=dirname) time_steps = case.time_steps() - tss_snapshot = range(0, len(time_steps), n) - print(case.name, case.id, 'Number of time_steps: ' + str(len(time_steps))) - print('Number of time_steps for snapshoting: ' + str(len(tss_snapshot))) + print('Number of time_steps: ' + str(len(time_steps))) view = case.views()[0] for property in property_list: view.apply_cell_result(result_type='DYNAMIC_NATIVE', result_variable=property) - for ts_snapshot in tss_snapshot: - resinsight.commands.set_time_step(case_id = case.id, time_step = ts_snapshot) - resinsight.commands.export_snapshots(type='VIEWS', case_id=case.id) # ‘ALL’, ‘VIEWS’ or ‘PLOTS’ default is 'ALL' + for time_step in range(0, len(time_steps), 10): + view.set_time_step(time_step = time_step) + view.export_snapshot() diff --git a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/InputPropTestAsync.py b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/InputPropTestAsync.py index ca2390d92c..8b1f43dcef 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/InputPropTestAsync.py +++ b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/InputPropTestAsync.py @@ -19,17 +19,17 @@ def create_result(poro_chunks, permx_chunks): resinsight = rips.Instance.find() start = time.time() -case = resinsight.project.case(id=0) +case = resinsight.project.case(case_id=0) # Get a generator for the poro results. The generator will provide a chunk each time it is iterated -poro_chunks = case.properties.active_cell_property_async('STATIC_NATIVE', 'PORO', 0) +poro_chunks = case.active_cell_property_async('STATIC_NATIVE', 'PORO', 0) # Get a generator for the permx results. The generator will provide a chunk each time it is iterated -permx_chunks = case.properties.active_cell_property_async('STATIC_NATIVE', 'PERMX', 0) +permx_chunks = case.active_cell_property_async('STATIC_NATIVE', 'PERMX', 0) # Send back the result with the result provided by a generator object. # Iterating the result generator will cause the script to read from the poro and permx generators # And return the result of each iteration -case.properties.set_active_cell_property_async(create_result(poro_chunks, permx_chunks), +case.set_active_cell_property_async(create_result(poro_chunks, permx_chunks), 'GENERATED', 'POROPERMXAS', 0) end = time.time() diff --git a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/InputPropTestSync.py b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/InputPropTestSync.py index b38de90a41..a295824fd8 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/InputPropTestSync.py +++ b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/InputPropTestSync.py @@ -9,12 +9,12 @@ import grpc resinsight = rips.Instance.find() start = time.time() -case = resinsight.project.case(id=0) +case = resinsight.project.case(case_id=0) # Read poro result into list -poro_results = case.properties.active_cell_property('STATIC_NATIVE', 'PORO', 0) +poro_results = case.active_cell_property('STATIC_NATIVE', 'PORO', 0) # Read permx result into list -permx_results = case.properties.active_cell_property('STATIC_NATIVE', 'PERMX', 0) +permx_results = case.active_cell_property('STATIC_NATIVE', 'PERMX', 0) # Generate output result results = [] @@ -23,7 +23,7 @@ for (poro, permx) in zip(poro_results, permx_results): try: # Send back output result - case.properties.set_active_cell_property(results, 'GENERATED', 'POROPERMXSY', 0) + case.set_active_cell_property(results, 'GENERATED', 'POROPERMXSY', 0) except grpc.RpcError as e: print("Exception Received: ", e) diff --git a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SelectedCases.py b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SelectedCases.py index be6431e2c1..1f83cee761 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SelectedCases.py +++ b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SelectedCases.py @@ -14,7 +14,7 @@ if resinsight is not None: print ("Got " + str(len(cases)) + " cases: ") for case in cases: print(case.name) - for property in case.properties.available('DYNAMIC_NATIVE'): + for property in case.available_properties('DYNAMIC_NATIVE'): print(property) diff --git a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SetCellResult.py b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SetCellResult.py index f527d6d3db..1c216bed5a 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SetCellResult.py +++ b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SetCellResult.py @@ -5,5 +5,5 @@ import rips resinsight = rips.Instance.find() -view = resinsight.project.view(0) -view.apply_cell_result(resultType='STATIC_NATIVE', resultVariable='DX') +view = resinsight.project.view(view_id=0) +view.apply_cell_result(result_type='STATIC_NATIVE', result_variable='DX') diff --git a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SetFlowDiagnosticsResult.py b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SetFlowDiagnosticsResult.py index 1fdbcc91e5..521548eccc 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SetFlowDiagnosticsResult.py +++ b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SetFlowDiagnosticsResult.py @@ -7,7 +7,7 @@ import rips # Connect to ResInsight instance resinsight = rips.Instance.find() -view = resinsight.project.view(0) +view = resinsight.project.view(view_id=0) #view.apply_flow_diagnostics_cell_result(result_variable='Fraction', # selection_mode='FLOW_TR_INJ_AND_PROD') diff --git a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SetGridProperties.py b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SetGridProperties.py index 837ccf0833..12f6d29449 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SetGridProperties.py +++ b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SetGridProperties.py @@ -5,7 +5,7 @@ import rips resinsight = rips.Instance.find() -case = resinsight.project.case(id=0) +case = resinsight.project.case(case_id=0) total_cell_count = case.cell_count().reservoir_cell_count values = [] @@ -13,5 +13,5 @@ for i in range(0, total_cell_count): values.append(i % 2 * 0.75); print("Applying values to full grid") -case.properties.set_grid_property(values, 'DYNAMIC_NATIVE', 'SOIL', 0) +case.set_grid_property(values, 'DYNAMIC_NATIVE', 'SOIL', 0) diff --git a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SoilAverageAsync.py b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SoilAverageAsync.py index 9aa25c50d3..e8c5f064c9 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SoilAverageAsync.py +++ b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SoilAverageAsync.py @@ -11,7 +11,7 @@ resinsight = rips.Instance.find() start = time.time() # Get the case with case id 0 -case = resinsight.project.case(id=0) +case = resinsight.project.case(case_id=0) # Get a list of all time steps timeSteps = case.time_steps() @@ -20,7 +20,7 @@ averages = [] for i in range(0, len(timeSteps)): # Get the results from time step i asynchronously # It actually returns a generator object almost immediately - result_chunks = case.properties.active_cell_property_async('DYNAMIC_NATIVE', 'SOIL', i) + result_chunks = case.active_cell_property_async('DYNAMIC_NATIVE', 'SOIL', i) mysum = 0.0 count = 0 # Loop through and append the average. each time we loop resultChunks diff --git a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SoilAverageSync.py b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SoilAverageSync.py index ca82dd4218..92b763c8be 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SoilAverageSync.py +++ b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SoilAverageSync.py @@ -8,10 +8,9 @@ import time resinsight = rips.Instance.find() start = time.time() -case = resinsight.project.case(id=0) # Get the case with case id 0 -case = resinsight.project.case(id=0) +case = resinsight.project.case(case_id=0) # Get a list of all time steps time_steps = case.time_steps() @@ -19,7 +18,7 @@ time_steps = case.time_steps() averages = [] for i in range(0, len(time_steps)): # Get a list of all the results for time step i - results = case.properties.active_cell_property('DYNAMIC_NATIVE', 'SOIL', i) + results = case.active_cell_property('DYNAMIC_NATIVE', 'SOIL', i) mysum = sum(results) averages.append(mysum/len(results)) diff --git a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SoilPorvAsync.py b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SoilPorvAsync.py index fbc6369d9a..531a8c1b10 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SoilPorvAsync.py +++ b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SoilPorvAsync.py @@ -18,11 +18,11 @@ def create_result(soil_chunks, porv_chunks): resinsight = rips.Instance.find() start = time.time() -case = resinsight.project.case(id=0) +case = resinsight.project.case(case_id=0) timeStepInfo = case.time_steps() # Get a generator for the porv results. The generator will provide a chunk each time it is iterated -porv_chunks = case.properties.active_cell_property_async('STATIC_NATIVE', 'PORV', 0) +porv_chunks = case.active_cell_property_async('STATIC_NATIVE', 'PORV', 0) # Read the static result into an array, so we don't have to transfer it for each iteration # Note we use the async method even if we synchronise here, because we need the values chunked @@ -33,11 +33,11 @@ for porv_chunk in porv_chunks: for i in range (0, len(timeStepInfo)): # Get a generator object for the SOIL property for time step i - soil_chunks = case.properties.active_cell_property_async('DYNAMIC_NATIVE', 'SOIL', i) + soil_chunks = case.active_cell_property_async('DYNAMIC_NATIVE', 'SOIL', i) # Create the generator object for the SOIL * PORV derived result result_generator = create_result(soil_chunks, iter(porv_array)) # Send back the result asynchronously with a generator object - case.properties.set_active_cell_property_async(result_generator, 'GENERATED', 'SOILPORVAsync', i) + case.set_active_cell_property_async(result_generator, 'GENERATED', 'SOILPORVAsync', i) end = time.time() print("Time elapsed: ", end - start) diff --git a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SoilPorvSync.py b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SoilPorvSync.py index 459ca922b1..13a51f0d97 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SoilPorvSync.py +++ b/ApplicationCode/GrpcInterface/Python/rips/PythonExamples/SoilPorvSync.py @@ -7,15 +7,15 @@ import time resinsight = rips.Instance.find() start = time.time() -case = resinsight.project.case(id=0) +case = resinsight.project.case(case_id=0) # Read the full porv result -porv_results = case.properties.active_cell_property('STATIC_NATIVE', 'PORV', 0) +porv_results = case.active_cell_property('STATIC_NATIVE', 'PORV', 0) time_step_info = case.time_steps() for i in range (0, len(time_step_info)): # Read the full SOIl result for time step i - soil_results = case.properties.active_cell_property('DYNAMIC_NATIVE', 'SOIL', i) + soil_results = case.active_cell_property('DYNAMIC_NATIVE', 'SOIL', i) # Generate the result by looping through both lists in order results = [] @@ -23,7 +23,7 @@ for i in range (0, len(time_step_info)): results.append(soil * porv) # Send back result - case.properties.set_active_cell_property(results, 'GENERATED', 'SOILPORVSync', i) + case.set_active_cell_property(results, 'GENERATED', 'SOILPORVSync', i) end = time.time() print("Time elapsed: ", end - start) diff --git a/ApplicationCode/GrpcInterface/Python/rips/__init__.py b/ApplicationCode/GrpcInterface/Python/rips/__init__.py index 1988c72ad2..f004c2a2a3 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/__init__.py +++ b/ApplicationCode/GrpcInterface/Python/rips/__init__.py @@ -1,9 +1,12 @@ name = "rips" -from rips.Case import Case -from rips.Grid import Grid -from rips.Properties import Properties -from rips.Instance import Instance -from rips.Commands import Commands -from rips.PdmObject import PdmObject -from rips.View import View -from rips.Project import Project \ No newline at end of file + +import os +import sys +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'generated')) + +from rips.case import Case +from rips.grid import Grid +from rips.instance import Instance +from rips.pdmobject import PdmObject +from rips.view import View +from rips.project import Project \ No newline at end of file diff --git a/ApplicationCode/GrpcInterface/Python/rips/case.py b/ApplicationCode/GrpcInterface/Python/rips/case.py new file mode 100644 index 0000000000..263bfda163 --- /dev/null +++ b/ApplicationCode/GrpcInterface/Python/rips/case.py @@ -0,0 +1,719 @@ +# pylint: disable=no-member +# pylint: disable=too-many-arguments +# pylint: disable=too-many-public-methods +# pylint: disable=no-self-use + +""" +Module containing the Case class +""" + +import grpc + +import rips.generated.Case_pb2 as Case_pb2 +import rips.generated.Case_pb2_grpc as Case_pb2_grpc +import rips.generated.Commands_pb2 as Cmd +import rips.generated.Properties_pb2 as Properties_pb2 +import rips.generated.Properties_pb2_grpc as Properties_pb2_grpc + +from rips.grid import Grid +from rips.pdmobject import PdmObject +from rips.view import View + +class Case(PdmObject): + """ResInsight case class + + Operate on a ResInsight case specified by a Case Id integer. + Not meant to be constructed separately but created by one of the following + methods in Project: loadCase, case, allCases, selectedCasesq + + Attributes: + id (int): Case Id corresponding to case Id in ResInsight project. + name (str): Case name + group_id (int): Case Group id + chunkSize(int): The size of each chunk during value streaming. + A good chunk size is 64KiB = 65536B. + Meaning the ideal number of doubles would be 8192. + However we need overhead space, so the default is 8160. + This leaves 256B for overhead. + """ + def __init__(self, channel, case_id): + # Private properties + self.__channel = channel + self.__case_stub = Case_pb2_grpc.CaseStub(channel) + self.__request = Case_pb2.CaseRequest(id=case_id) + + info = self.__case_stub.GetCaseInfo(self.__request) + self.__properties_stub = Properties_pb2_grpc.PropertiesStub( + self.__channel) + PdmObject.__init__(self, self.__case_stub.GetPdmObject(self.__request), + self.__channel) + + # Public properties + self.case_id = case_id + self.name = info.name + self.chunk_size = 8160 + + def __grid_count(self): + """Get number of grids in the case""" + try: + return self.__case_stub.GetGridCount(self.__request).count + except grpc.RpcError as exception: + if exception.code() == grpc.StatusCode.NOT_FOUND: + return 0 + print("ERROR: ", exception) + return 0 + + def __generate_property_input_iterator(self, values_iterator, parameters): + chunk = Properties_pb2.PropertyInputChunk() + chunk.params.CopyFrom(parameters) + yield chunk + + for values in values_iterator: + valmsg = Properties_pb2.PropertyChunk(values=values) + chunk.values.CopyFrom(valmsg) + yield chunk + + def __generate_property_input_chunks(self, array, parameters): + index = -1 + while index < len(array): + chunk = Properties_pb2.PropertyInputChunk() + if index is -1: + chunk.params.CopyFrom(parameters) + index += 1 + else: + actual_chunk_size = min(len(array) - index + 1, self.chunk_size) + chunk.values.CopyFrom( + Properties_pb2.PropertyChunk(values=array[index:index + + actual_chunk_size])) + index += actual_chunk_size + + yield chunk + # Final empty message to signal completion + chunk = Properties_pb2.PropertyInputChunk() + yield chunk + + def grid_path(self): + """Get path of the current grid case + + Returns: path string + """ + return self.get_value("CaseFileName") + + def grid(self, index): + """Get Grid of a given index. Returns a rips Grid object + + Arguments: + index (int): The grid index + + Returns: Grid object + """ + return Grid(index, self, self.__channel) + + def grids(self): + """Get a list of all rips Grid objects in the case""" + grid_list = [] + for i in range(0, self.__grid_count()): + grid_list.append(Grid(i, self, self.__channel)) + return grid_list + + def replace(self, new_grid_file): + """Replace the current case grid with a new grid loaded from file + + Arguments: + new_egrid_file (str): path to EGRID file + """ + self._execute_command(replaceCase=Cmd.ReplaceCaseRequest( + newGridFile=new_grid_file, caseId=self.case_id)) + self.__init__(self.__channel, self.case_id) + + def cell_count(self, porosity_model="MATRIX_MODEL"): + """Get a cell count object containing number of active cells and + total number of cells + + Arguments: + porosity_model (str): String representing an enum. + must be 'MATRIX_MODEL' or 'FRACTURE_MODEL'. + Returns: + Cell Count object with the following integer attributes: + active_cell_count: number of active cells + reservoir_cell_count: total number of reservoir cells + """ + porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model) + request = Case_pb2.CellInfoRequest(case_request=self.__request, + porosity_model=porosity_model_enum) + return self.__case_stub.GetCellCount(request) + + def cell_info_for_active_cells_async(self, porosity_model="MATRIX_MODEL"): + """Get Stream of cell info objects for current case + + Arguments: + porosity_model(str): String representing an enum. + must be 'MATRIX_MODEL' or 'FRACTURE_MODEL'. + + Returns: + Stream of **CellInfo** objects + + See cell_info_for_active_cells() for detalis on the **CellInfo** class. + """ + porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model) + request = Case_pb2.CellInfoRequest(case_request=self.__request, + porosity_model=porosity_model_enum) + return self.__case_stub.GetCellInfoForActiveCells(request) + + def cell_info_for_active_cells(self, porosity_model="MATRIX_MODEL"): + """Get list of cell info objects for current case + + Arguments: + porosity_model(str): String representing an enum. + must be 'MATRIX_MODEL' or 'FRACTURE_MODEL'. + + Returns: + List of **CellInfo** objects + + ### CellInfo class description + + Parameter | Description | Type + ------------------------- | --------------------------------------------- | ----- + grid_index | Index to grid | Integer + parent_grid_index | Index to parent grid | Integer + coarsening_box_index | Index to coarsening box | Integer + local_ijk | Cell index in IJK directions of local grid | Vec3i + parent_ijk | Cell index in IJK directions of parent grid | Vec3i + + ### Vec3i class description + + Parameter | Description | Type + ---------------- | -------------------------------------------- | ----- + i | I grid index | Integer + j | J grid index | Integer + k | K grid index | Integer + + """ + active_cell_info_chunks = self.cell_info_for_active_cells_async( + porosity_model=porosity_model) + received_active_cells = [] + for active_cell_chunk in active_cell_info_chunks: + for active_cell in active_cell_chunk.data: + received_active_cells.append(active_cell) + return received_active_cells + + def time_steps(self): + """Get a list containing all time steps + + The time steps are defined by the class **TimeStepDate** : + + Type | Name + --------- | ---------- + int | year + int | month + int | day + int | hour + int | minute + int | second + + + """ + return self.__case_stub.GetTimeSteps(self.__request).dates + + def days_since_start(self): + """Get a list of decimal values representing days since the start of the simulation""" + return self.__case_stub.GetDaysSinceStart(self.__request).day_decimals + + def views(self): + """Get a list of views belonging to a case""" + pdm_objects = self.children("ReservoirViews") + view_list = [] + for pdm_object in pdm_objects: + view_list.append(View(pdm_object)) + return view_list + + def view(self, view_id): + """Get a particular view belonging to a case by providing view id + Arguments: + view_id(int): view id + + Returns: a view object + + """ + views = self.views() + for view_object in views: + if view_object.view_id == view_id: + return view_object + return None + + def create_view(self): + """Create a new view in the current case""" + return self.view( + self._execute_command(createView=Cmd.CreateViewRequest( + caseId=self.case_id)).createViewResult.viewId) + + def export_snapshots_of_all_views(self, prefix=""): + """ Export snapshots for all views in the case + + Arguments: + prefix (str): Exported file name prefix + + """ + return self._execute_command( + exportSnapshots=Cmd.ExportSnapshotsRequest( + type="VIEWS", prefix=prefix, caseId=self.case_id, viewId=-1)) + + def export_well_path_completions( + self, + time_step, + well_path_names, + file_split, + compdat_export="TRANSMISSIBILITIES", + include_perforations=True, + include_fishbones=True, + fishbones_exclude_main_bore=True, + combination_mode="INDIVIDUALLY", + ): + """ + Export well path completions for the current case to file + + Parameter | Description | Type + ----------------------------| ------------------------------------------------ | ----- + time_step | Time step to export for | Integer + well_path_names | List of well path names | List + file_split | Split type: +
    +
  • 'UNIFIED_FILE'
  • +
  • 'SPLIT_ON_WELL'
  • +
  • 'SPLIT_ON_WELL_AND_COMPLETION_TYPE'
  • +
| String enum + compdat_export | Compdat export type: +
    +
  • 'TRANSMISSIBILITIES'
  • +
  • 'WPIMULT_AND_DEFAULT_CONNECTION_FACTORS'
  • +
| String enum + include_perforations | Export perforations? | bool + include_fishbones | Export fishbones? | bool + fishbones_exclude_main_bore | Exclude main bore when exporting fishbones? | bool + combination_mode | Combination mode: +
    +
  • 'INDIVIDUALLY'
  • +
  • 'COMBINED'
  • +
| String enum + """ + if isinstance(well_path_names, str): + well_path_names = [well_path_names] + return self._execute_command( + exportWellPathCompletions=Cmd.ExportWellPathCompRequest( + caseId=self.case_id, + timeStep=time_step, + wellPathNames=well_path_names, + fileSplit=file_split, + compdatExport=compdat_export, + includePerforations=include_perforations, + includeFishbones=include_fishbones, + excludeMainBoreForFishbones=fishbones_exclude_main_bore, + combinationMode=combination_mode, + )) + + def export_msw(self, well_path): + """ + Export Eclipse Multi-segment-well model to file + + Arguments: + well_path(str): Well path name + """ + return self._execute_command(exportMsw=Cmd.ExportMswRequest( + caseId=self.case_id, wellPath=well_path)) + + def create_multiple_fractures( + self, + template_id, + well_path_names, + min_dist_from_well_td, + max_fractures_per_well, + top_layer, + base_layer, + spacing, + action, + ): + """ + Create Multiple Fractures in one go + + Parameter | Description | Type + -----------------------| ---------------------------------- -| ----- + template_id | Id of the template | Integer + well_path_names | List of well path names | List of Strings + min_dist_from_well_td | Minimum distance from well TD | Double + max_fractures_per_well | Max number of fractures per well | Integer + top_layer | Top grid k-level for fractures | Integer + base_layer | Base grid k-level for fractures | Integer + spacing | Spacing between fractures | Double + action | 'APPEND_FRACTURES' or 'REPLACE_FRACTURES' | String enum + """ + if isinstance(well_path_names, str): + well_path_names = [well_path_names] + return self._execute_command( + createMultipleFractures=Cmd.MultipleFracRequest( + caseId=self.case_id, + templateId=template_id, + wellPathNames=well_path_names, + minDistFromWellTd=min_dist_from_well_td, + maxFracturesPerWell=max_fractures_per_well, + topLayer=top_layer, + baseLayer=base_layer, + spacing=spacing, + action=action, + )) + + def create_lgr_for_completion( + self, + time_step, + well_path_names, + refinement_i, + refinement_j, + refinement_k, + split_type, + ): + """ + Create a local grid refinement for the completions on the given well paths + + Parameter | Description | Type + --------------- | -------------------------------------- | ----- + time_steps | Time step index | Integer + well_path_names | List of well path names | List of Strings + refinement_i | Refinment in x-direction | Integer + refinement_j | Refinment in y-direction | Integer + refinement_k | Refinment in z-direction | Integer + split_type | Type of LGR split: +
    +
  • 'LGR_PER_CELL'
  • +
  • 'LGR_PER_COMPLETION'
  • +
  • 'LGR_PER_WELL'
  • +
| String enum + """ + if isinstance(well_path_names, str): + well_path_names = [well_path_names] + return self._execute_command( + createLgrForCompletions=Cmd.CreateLgrForCompRequest( + caseId=self.case_id, + timeStep=time_step, + wellPathNames=well_path_names, + refinementI=refinement_i, + refinementJ=refinement_j, + refinementK=refinement_k, + splitType=split_type, + )) + + def create_saturation_pressure_plots(self): + """ + Create saturation pressure plots for the current case + """ + case_ids = [self.case_id] + return self._execute_command( + createSaturationPressurePlots=Cmd.CreateSatPressPlotRequest( + caseIds=case_ids)) + + def export_flow_characteristics( + self, + time_steps, + injectors, + producers, + file_name, + minimum_communication=0.0, + aquifer_cell_threshold=0.1, + ): + """ Export Flow Characteristics data to text file in CSV format + + Parameter | Description | Type + ------------------------- | --------------------------------------------- | ----- + time_steps | Time step indices | List of Integer + injectors | Injector names | List of Strings + producers | Producer names | List of Strings + file_name | Export file name | Integer + minimum_communication | Minimum Communication, defaults to 0.0 | Integer + aquifer_cell_threshold | Aquifer Cell Threshold, defaults to 0.1 | Integer + + """ + if isinstance(time_steps, int): + time_steps = [time_steps] + if isinstance(injectors, str): + injectors = [injectors] + if isinstance(producers, str): + producers = [producers] + return self._execute_command( + exportFlowCharacteristics=Cmd.ExportFlowInfoRequest( + caseId=self.case_id, + timeSteps=time_steps, + injectors=injectors, + producers=producers, + fileName=file_name, + minimumCommunication=minimum_communication, + aquiferCellThreshold=aquifer_cell_threshold, + )) + + def available_properties(self, + property_type, + porosity_model="MATRIX_MODEL"): + """Get a list of available properties + + Arguments: + property_type (str): string corresponding to property_type enum. Choices: + - DYNAMIC_NATIVE + - STATIC_NATIVE + - SOURSIMRL + - GENERATED + - INPUT_PROPERTY + - FORMATION_NAMES + - FLOW_DIAGNOSTICS + - INJECTION_FLOODING + + porosity_model(str): 'MATRIX_MODEL' or 'FRACTURE_MODEL'. + """ + + property_type_enum = Properties_pb2.PropertyType.Value(property_type) + porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model) + request = Properties_pb2.AvailablePropertiesRequest( + case_request=self.__request, + property_type=property_type_enum, + porosity_model=porosity_model_enum, + ) + return self.__properties_stub.GetAvailableProperties( + request).property_names + + def active_cell_property_async(self, + property_type, + property_name, + time_step, + porosity_model="MATRIX_MODEL"): + """Get a cell property for all active cells. Async, so returns an iterator + + Arguments: + property_type(str): string enum. See available() + property_name(str): name of an Eclipse property + time_step(int): the time step for which to get the property for + porosity_model(str): string enum. See available() + + Returns: + An iterator to a chunk object containing an array of double values + Loop through the chunks and then the values within the chunk to get all values. + """ + property_type_enum = Properties_pb2.PropertyType.Value(property_type) + porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model) + request = Properties_pb2.PropertyRequest( + case_request=self.__request, + property_type=property_type_enum, + property_name=property_name, + time_step=time_step, + porosity_model=porosity_model_enum, + ) + for chunk in self.__properties_stub.GetActiveCellProperty(request): + yield chunk + + def active_cell_property(self, + property_type, + property_name, + time_step, + porosity_model="MATRIX_MODEL"): + """Get a cell property for all active cells. Sync, so returns a list + + Arguments: + property_type(str): string enum. See available() + property_name(str): name of an Eclipse property + time_step(int): the time step for which to get the property for + porosity_model(str): string enum. See available() + + Returns: + A list containing double values + Loop through the chunks and then the values within the chunk to get all values. + """ + all_values = [] + generator = self.active_cell_property_async(property_type, + property_name, time_step, + porosity_model) + for chunk in generator: + for value in chunk.values: + all_values.append(value) + return all_values + + def grid_property_async( + self, + property_type, + property_name, + time_step, + grid_index=0, + porosity_model="MATRIX_MODEL", + ): + """Get a cell property for all grid cells. Async, so returns an iterator + + Arguments: + property_type(str): string enum. See available() + property_name(str): name of an Eclipse property + time_step(int): the time step for which to get the property for + gridIndex(int): index to the grid we're getting values for + porosity_model(str): string enum. See available() + + Returns: + An iterator to a chunk object containing an array of double values + Loop through the chunks and then the values within the chunk to get all values. + """ + property_type_enum = Properties_pb2.PropertyType.Value(property_type) + porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model) + request = Properties_pb2.PropertyRequest( + case_request=self.__request, + property_type=property_type_enum, + property_name=property_name, + time_step=time_step, + grid_index=grid_index, + porosity_model=porosity_model_enum, + ) + for chunk in self.__properties_stub.GetGridProperty(request): + yield chunk + + def grid_property( + self, + property_type, + property_name, + time_step, + grid_index=0, + porosity_model="MATRIX_MODEL", + ): + """Get a cell property for all grid cells. Synchronous, so returns a list + + Arguments: + property_type(str): string enum. See available() + property_name(str): name of an Eclipse property + time_step(int): the time step for which to get the property for + grid_index(int): index to the grid we're getting values for + porosity_model(str): string enum. See available() + + Returns: + A list of double values + """ + all_values = [] + generator = self.grid_property_async(property_type, property_name, + time_step, grid_index, + porosity_model) + for chunk in generator: + for value in chunk.values: + all_values.append(value) + return all_values + + def set_active_cell_property_async( + self, + values_iterator, + property_type, + property_name, + time_step, + porosity_model="MATRIX_MODEL", + ): + """Set cell property for all active cells Async. Takes an iterator to the input values + + Arguments: + values_iterator(iterator): an iterator to the properties to be set + property_type(str): string enum. See available() + property_name(str): name of an Eclipse property + time_step(int): the time step for which to get the property for + porosity_model(str): string enum. See available() + """ + property_type_enum = Properties_pb2.PropertyType.Value(property_type) + porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model) + request = Properties_pb2.PropertyRequest( + case_request=self.__request, + property_type=property_type_enum, + property_name=property_name, + time_step=time_step, + porosity_model=porosity_model_enum, + ) + + request_iterator = self.__generate_property_input_iterator( + values_iterator, request) + self.__properties_stub.SetActiveCellProperty(request_iterator) + + def set_active_cell_property( + self, + values, + property_type, + property_name, + time_step, + porosity_model="MATRIX_MODEL", + ): + """Set a cell property for all active cells. + + Arguments: + values(list): a list of double precision floating point numbers + property_type(str): string enum. See available() + property_name(str): name of an Eclipse property + time_step(int): the time step for which to get the property for + porosity_model(str): string enum. See available() + """ + property_type_enum = Properties_pb2.PropertyType.Value(property_type) + porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model) + request = Properties_pb2.PropertyRequest( + case_request=self.__request, + property_type=property_type_enum, + property_name=property_name, + time_step=time_step, + porosity_model=porosity_model_enum, + ) + request_iterator = self.__generate_property_input_chunks( + values, request) + reply = self.__properties_stub.SetActiveCellProperty(request_iterator) + if reply.accepted_value_count < len(values): + raise IndexError + + def set_grid_property( + self, + values, + property_type, + property_name, + time_step, + grid_index=0, + porosity_model="MATRIX_MODEL", + ): + """Set a cell property for all grid cells. + + Arguments: + values(list): a list of double precision floating point numbers + property_type(str): string enum. See available() + property_name(str): name of an Eclipse property + time_step(int): the time step for which to get the property for + grid_index(int): index to the grid we're setting values for + porosity_model(str): string enum. See available() + """ + property_type_enum = Properties_pb2.PropertyType.Value(property_type) + porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model) + request = Properties_pb2.PropertyRequest( + case_request=self.__request, + property_type=property_type_enum, + property_name=property_name, + time_step=time_step, + grid_index=grid_index, + porosity_model=porosity_model_enum, + ) + request_iterator = self.__generate_property_input_chunks( + values, request) + reply = self.__properties_stub.SetGridProperty(request_iterator) + if reply.accepted_value_count < len(values): + raise IndexError + + def export_property( + self, + time_step, + property_name, + eclipse_keyword=property, + undefined_value=0.0, + export_file=property, + ): + """ Export an Eclipse property + + Arguments: + time_step (int): time step index + property_name (str): property to export + eclipse_keyword (str): Keyword used in export header. Defaults: value of property + undefined_value (double): Value to use for undefined values. Defaults to 0.0 + export_file (str): File name for export. Defaults to the value of property parameter + """ + return self._execute_command(exportProperty=Cmd.ExportPropertyRequest( + caseId=self.case_id, + timeStep=time_step, + property=property_name, + eclipseKeyword=eclipse_keyword, + undefinedValue=undefined_value, + exportFile=export_file, + )) diff --git a/ApplicationCode/GrpcInterface/Python/rips/grid.py b/ApplicationCode/GrpcInterface/Python/rips/grid.py new file mode 100644 index 0000000000..5858f58429 --- /dev/null +++ b/ApplicationCode/GrpcInterface/Python/rips/grid.py @@ -0,0 +1,33 @@ +# pylint: disable=too-few-public-methods + +""" +Module containing the Grid class, containing information +about Case grids. +""" + +import rips.generated.Case_pb2 as Case_pb2 +import rips.generated.Grid_pb2 as Grid_pb2 +import rips.generated.Grid_pb2_grpc as Grid_pb2_grpc + +class Grid: + """Grid Information. Not meant to be constructed separately + + Create Grid objects using mathods on Case: Grid() and Grids() + """ + def __init__(self, index, case, channel): + self.__channel = channel + self.__stub = Grid_pb2_grpc.GridStub(self.__channel) + + self.case = case + self.index = index + + def dimensions(self): + """The dimensions in i, j, k direction + + Returns: + Vec3i: class with integer attributes i, j, k giving extent in all three dimensions. + """ + case_request = Case_pb2.CaseRequest(id=self.case.case_id) + return self.__stub.GetDimensions( + Grid_pb2.GridRequest(case_request=case_request, + grid_index=self.index)).dimensions diff --git a/ApplicationCode/GrpcInterface/Python/rips/gridcasegroup.py b/ApplicationCode/GrpcInterface/Python/rips/gridcasegroup.py new file mode 100644 index 0000000000..7c11e7a439 --- /dev/null +++ b/ApplicationCode/GrpcInterface/Python/rips/gridcasegroup.py @@ -0,0 +1,73 @@ +""" +Grid Case Group statistics module +""" + +from rips.pdmobject import PdmObject +from rips.view import View +from rips.case import Case + +import rips.generated.Commands_pb2 as Cmd + +class GridCaseGroup(PdmObject): + """ResInsight Grid Case Group class + + Operate on a ResInsight case group specified by a Case Group Id integer. + + Attributes: + group_id (int): Grid Case Group Id corresponding to case group Id in ResInsight project. + """ + def __init__(self, pdm_object): + self.group_id = pdm_object.get_value("GroupId") + PdmObject.__init__(self, pdm_object._pb2_object, pdm_object._channel) + + def create_statistics_case(self): + """Create a Statistics case in the Grid Case Group + + Returns: + A new Case + """ + command_reply = self._execute_command( + createStatisticsCase=Cmd.CreateStatisticsCaseRequest( + caseGroupId=self.group_id)) + return Case(self.channel, + command_reply.createStatisticsCaseResult.caseId) + + def statistics_cases(self): + """Get a list of all statistics cases in the Grid Case Group""" + stat_case_collection = self.children("StatisticsCaseCollection")[0] + return stat_case_collection.children("Reservoirs") + + def views(self): + """Get a list of views belonging to a grid case group""" + pdm_objects = self.descendants("ReservoirView") + view_list = [] + for pdm_object in pdm_objects: + view_list.append(View(pdm_object)) + return view_list + + def view(self, view_id): + """Get a particular view belonging to a case group by providing view id + Arguments: + id(int): view id + + Returns: a view object + + """ + views = self.views() + for view_object in views: + if view_object.id == view_id: + return view_object + return None + + def compute_statistics(self, case_ids=None): + """ Compute statistics for the given case ids + + Arguments: + case_ids(list): list of case ids. If this is None all cases in group are included + + """ + if case_ids is None: + case_ids = [] + return self._execute_command( + computeCaseGroupStatistics=Cmd.ComputeCaseGroupStatRequest( + caseIds=case_ids, caseGroupId=self.group_id)) diff --git a/ApplicationCode/GrpcInterface/Python/rips/instance.py b/ApplicationCode/GrpcInterface/Python/rips/instance.py new file mode 100644 index 0000000000..d1d87a2f75 --- /dev/null +++ b/ApplicationCode/GrpcInterface/Python/rips/instance.py @@ -0,0 +1,269 @@ +# pylint: disable=no-self-use +""" +The main entry point for ResInsight connections +The Instance class contained have static methods launch and find for +creating connections to ResInsight +""" + +import os +import socket +import logging +import time + +import grpc + +import rips.generated.App_pb2 as App_pb2 +import rips.generated.App_pb2_grpc as App_pb2_grpc +import rips.generated.Commands_pb2 as Cmd +import rips.generated.Commands_pb2_grpc as CmdRpc +from rips.generated.Definitions_pb2 import Empty + +import rips.generated.RiaVersionInfo as RiaVersionInfo + +from rips.project import Project + + +class Instance: + """The ResInsight Instance class. Use to launch or find existing ResInsight instances + + Attributes: + launched (bool): Tells us whether the application was launched as a new process. + If the application was launched we may need to close it when exiting the script. + commands (Commands): Command executor. Set when creating an instance. + project (Project): Current project in ResInsight. + Set when creating an instance and updated when opening/closing projects. + """ + @staticmethod + def __is_port_in_use(port): + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as my_socket: + my_socket.settimeout(0.2) + return my_socket.connect_ex(('localhost', port)) == 0 + + @staticmethod + def launch(resinsight_executable='', + console=False, + launch_port=-1, + command_line_parameters=None): + """ Launch a new Instance of ResInsight. This requires the environment variable + RESINSIGHT_EXECUTABLE to be set or the parameter resinsight_executable to be provided. + The RESINSIGHT_GRPC_PORT environment variable can be set to an alternative port number. + + Args: + resinsight_executable (str): Path to a valid ResInsight executable. If set + will take precedence over what is provided in the RESINSIGHT_EXECUTABLE + environment variable. + console (bool): If True, launch as console application, without GUI. + launch_port(int): If -1 will use the default port 50051 or RESINSIGHT_GRPC_PORT + if anything else, ResInsight will try to launch with this port + command_line_parameters(list): Additional parameters as string entries in the list. + Returns: + Instance: an instance object if it worked. None if not. + """ + + port = 50051 + port_env = os.environ.get('RESINSIGHT_GRPC_PORT') + if port_env: + port = int(port_env) + if launch_port is not -1: + port = launch_port + + if not resinsight_executable: + resinsight_executable = os.environ.get('RESINSIGHT_EXECUTABLE') + if not resinsight_executable: + print( + 'ERROR: Could not launch ResInsight because the environment variable' + ' RESINSIGHT_EXECUTABLE is not set') + return None + + while Instance.__is_port_in_use(port): + port += 1 + + print('Port ' + str(port)) + print('Trying to launch', resinsight_executable) + + if command_line_parameters is None: + command_line_parameters = [] + elif isinstance(command_line_parameters, str): + command_line_parameters = [str] + + parameters = ["ResInsight", "--server", + str(port)] + command_line_parameters + if console: + print("Launching as console app") + parameters.append("--console") + + # Stringify all parameters + for i in enumerate(parameters): + parameters[i] = str(parameters[i]) + + pid = os.spawnv(os.P_NOWAIT, resinsight_executable, parameters) + if pid: + instance = Instance(port=port, launched=True) + return instance + return None + + @staticmethod + def find(start_port=50051, end_port=50071): + """ Search for an existing Instance of ResInsight by testing ports. + + By default we search from port 50051 to 50071 or if the environment + variable RESINSIGHT_GRPC_PORT is set we search + RESINSIGHT_GRPC_PORT to RESINSIGHT_GRPC_PORT+20 + + Args: + start_port (int): start searching from this port + end_port (int): search up to but not including this port + """ + port_env = os.environ.get('RESINSIGHT_GRPC_PORT') + if port_env: + start_port = int(port_env) + end_port = start_port + 20 + + for try_port in range(start_port, end_port): + if Instance.__is_port_in_use(try_port): + return Instance(port=try_port) + + print( + 'Error: Could not find any ResInsight instances responding between ports ' + + str(start_port) + ' and ' + str(end_port)) + return None + + def __execute_command(self, **command_params): + return self.commands.Execute(Cmd.CommandParams(**command_params)) + + def __check_version(self): + try: + major_version_ok = self.major_version() == int( + RiaVersionInfo.RESINSIGHT_MAJOR_VERSION) + minor_version_ok = self.minor_version() == int( + RiaVersionInfo.RESINSIGHT_MINOR_VERSION) + return True, major_version_ok and minor_version_ok + except grpc.RpcError: + return False, False + + def __init__(self, port=50051, launched=False): + """ Attempts to connect to ResInsight at aa specific port on localhost + + Args: + port(int): port number + """ + logging.basicConfig() + location = "localhost:" + str(port) + + self.channel = grpc.insecure_channel(location, + options=[ + ('grpc.enable_http_proxy', + False) + ]) + self.launched = launched + self.commands = CmdRpc.CommandsStub(self.channel) + + # Main version check package + self.app = self.app = App_pb2_grpc.AppStub(self.channel) + + connection_ok = False + version_ok = False + + if self.launched: + for _ in range(0, 10): + connection_ok, version_ok = self.__check_version() + if connection_ok: + break + time.sleep(1.0) + else: + connection_ok, version_ok = self.__check_version() + + if not connection_ok: + if self.launched: + raise Exception('Error: Could not connect to resinsight at ', + location, + ' after trying 10 times with 1 second apart') + raise Exception('Error: Could not connect to resinsight at ', location) + if not version_ok: + raise Exception('Error: Wrong Version of ResInsight at ', location, + self.version_string(), " ", + self.client_version_string()) + + # Service packages + self.project = Project(self.channel) + + path = os.getcwd() + self.set_start_dir(path=path) + + def __version_message(self): + return self.app.GetVersion(Empty()) + + def set_start_dir(self, path): + """Set current start directory + + Arguments: + path (str): path to directory + + """ + return self.__execute_command(setStartDir=Cmd.FilePathRequest(path=path)) + + def set_export_folder(self, export_type, path, create_folder=False): + """ + Set the export folder used for all export functions + + Parameter | Description | Type + ---------------- | -------------------------------------------- | ----- + export_type | Type of export: 'COMPLETIONS', 'SNAPSHOTS' + 'PROPERTIES' or 'STATISTICS' | String + path | Path to folder | String + create_folder | Create folder if it doesn't exist? | Boolean + """ + return self.__execute_command(setExportFolder=Cmd.SetExportFolderRequest( + type=export_type, path=path, createFolder=create_folder)) + + def set_main_window_size(self, width, height): + """ + Set the main window size in pixels + Parameter | Description | Type + --------- | ---------------- | ----- + width | Width in pixels | Integer + height | Height in pixels | Integer + """ + return self.__execute_command(setMainWindowSize=Cmd.SetMainWindowSizeParams( + width=width, height=height)) + + def major_version(self): + """Get an integer with the major version number""" + return self.__version_message().major_version + + def minor_version(self): + """Get an integer with the minor version number""" + return self.__version_message().minor_version + + def patch_version(self): + """Get an integer with the patch version number""" + return self.__version_message().patch_version + + def version_string(self): + """Get a full version string, i.e. 2019.04.01""" + return str(self.major_version()) + "." + str( + self.minor_version()) + "." + str(self.patch_version()) + + def client_version_string(self): + """Get a full version string, i.e. 2019.04.01""" + version_string = RiaVersionInfo.RESINSIGHT_MAJOR_VERSION + "." + version_string += RiaVersionInfo.RESINSIGHT_MINOR_VERSION + "." + version_string += RiaVersionInfo.RESINSIGHT_PATCH_VERSION + return version_string + + def exit(self): + """Tell ResInsight instance to quit""" + print("Telling ResInsight to Exit") + return self.app.Exit(Empty()) + + def is_console(self): + """Returns true if the connected ResInsight instance is a console app""" + return self.app.GetRuntimeInfo( + Empty()).app_type == App_pb2.ApplicationTypeEnum.Value( + 'CONSOLE_APPLICATION') + + def is_gui(self): + """Returns true if the connected ResInsight instance is a GUI app""" + return self.app.GetRuntimeInfo( + Empty()).app_type == App_pb2.ApplicationTypeEnum.Value( + 'GUI_APPLICATION') diff --git a/ApplicationCode/GrpcInterface/Python/rips/PdmObject.py b/ApplicationCode/GrpcInterface/Python/rips/pdmobject.py similarity index 56% rename from ApplicationCode/GrpcInterface/Python/rips/PdmObject.py rename to ApplicationCode/GrpcInterface/Python/rips/pdmobject.py index d8aa4514bc..b2dedcac3d 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/PdmObject.py +++ b/ApplicationCode/GrpcInterface/Python/rips/pdmobject.py @@ -1,87 +1,95 @@ -import grpc -import os -import sys +# pylint: disable=no-self-use +""" +ResInsight caf::PdmObject connection module +""" +import rips.generated.PdmObject_pb2 as PdmObject_pb2 +import rips.generated.PdmObject_pb2_grpc as PdmObject_pb2_grpc +import rips.generated.Commands_pb2 as Cmd +import rips.generated.Commands_pb2_grpc as CmdRpc -sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'generated')) - -from Definitions_pb2 import Empty -import PdmObject_pb2 -import PdmObject_pb2_grpc class PdmObject: + """ + Generic ResInsight object. Corresponds to items in the Project Tree + """ + + def _execute_command(self, **command_params): + return self._commands.Execute(Cmd.CommandParams(**command_params)) + def __init__(self, pb2_object, channel): - self.pb2_object = pb2_object - self.channel = channel - self.pdm_object_stub = PdmObject_pb2_grpc.PdmObjectServiceStub(self.channel) - + self._pb2_object = pb2_object + self._channel = channel + self._pdm_object_stub = PdmObject_pb2_grpc.PdmObjectServiceStub( + self._channel) + self._commands = CmdRpc.CommandsStub(channel) + def address(self): """Get the unique address of the PdmObject - + Returns: A 64-bit unsigned integer address """ - return self.pb2_object.address + return self._pb2_object.address def class_keyword(self): """Get the class keyword in the ResInsight Data Model for the given PdmObject""" - return self.pb2_object.class_keyword + return self._pb2_object.class_keyword def keywords(self): """Get a list of all parameter keywords available in the object""" list_of_keywords = [] - for keyword in self.pb2_object.parameters: + for keyword in self._pb2_object.parameters: list_of_keywords.append(keyword) return list_of_keywords - + def print_object_info(self): """Print the structure and data content of the PdmObject""" - print ("Class Keyword: " + self.class_keyword()) + print("Class Keyword: " + self.class_keyword()) for keyword in self.keywords(): - print(keyword + " [" + type(self.get_value(keyword)).__name__ + "]: " + str(self.get_value(keyword))) + print(keyword + " [" + type(self.get_value(keyword)).__name__ + + "]: " + str(self.get_value(keyword))) def __to_value(self, value): if value.lower() == 'false': - return False - elif value.lower() == 'true': + return False + if value.lower() == 'true': return True - else: + try: + int_val = int(value) + return int_val + except ValueError: try: - int_val = int(value) - return int_val + float_val = float(value) + return float_val except ValueError: - try: - float_val = float(value) - return float_val - except ValueError: - # We may have a string. Strip internal start and end quotes - value = value.strip('\"') - if self.__islist(value): - return self.__makelist(value) - return value + # We may have a string. Strip internal start and end quotes + value = value.strip('\"') + if self.__islist(value): + return self.__makelist(value) + return value + def __from_value(self, value): if isinstance(value, bool): if value: return "true" - else: - return "false" - elif isinstance(value, list): + return "false" + if isinstance(value, list): list_of_strings = [] for val in value: list_of_strings.append(self.__from_value('\"' + val + '\"')) return "[" + ", ".join(list_of_strings) + "]" - else: - return str(value) + return str(value) def get_value(self, keyword): """Get the value associated with the provided keyword Arguments: keyword(str): A string containing the parameter keyword - + Returns: The value of the parameter. Can be int, str or list. """ - value = self.pb2_object.parameters[keyword] + value = self._pb2_object.parameters[keyword] return self.__to_value(value) def __islist(self, value): @@ -104,7 +112,7 @@ class PdmObject: See keyword documentation and/or print_object_info() to find the correct data type. """ - self.pb2_object.parameters[keyword] = self.__from_value(value) + self._pb2_object.parameters[keyword] = self.__from_value(value) def descendants(self, class_keyword): """Get a list of all project tree descendants matching the class keyword @@ -114,11 +122,13 @@ class PdmObject: Returns: A list of PdmObjects matching the keyword provided """ - request = PdmObject_pb2.PdmDescendantObjectRequest(object=self.pb2_object, child_keyword=class_keyword) - object_list = self.pdm_object_stub.GetDescendantPdmObjects(request).objects + request = PdmObject_pb2.PdmDescendantObjectRequest( + object=self._pb2_object, child_keyword=class_keyword) + object_list = self._pdm_object_stub.GetDescendantPdmObjects( + request).objects child_list = [] - for object in object_list: - child_list.append(PdmObject(object, self.channel)) + for pdm_object in object_list: + child_list.append(PdmObject(pdm_object, self._channel)) return child_list def children(self, child_field): @@ -128,11 +138,12 @@ class PdmObject: Returns: A list of PdmObjects inside the child_field """ - request = PdmObject_pb2.PdmChildObjectRequest(object=self.pb2_object, child_field=child_field) - object_list = self.pdm_object_stub.GetChildPdmObjects(request).objects + request = PdmObject_pb2.PdmChildObjectRequest(object=self._pb2_object, + child_field=child_field) + object_list = self._pdm_object_stub.GetChildPdmObjects(request).objects child_list = [] - for object in object_list: - child_list.append(PdmObject(object, self.channel)) + for pdm_object in object_list: + child_list.append(PdmObject(pdm_object, self._channel)) return child_list def ancestor(self, class_keyword): @@ -140,13 +151,11 @@ class PdmObject: Arguments: class_keyword[str]: A class keyword matching the type of class wanted """ - request = PdmObject_pb2.PdmParentObjectRequest(object=self.pb2_object, parent_keyword=class_keyword) - return PdmObject(self.pdm_object_stub.GetAncestorPdmObject(request), self.channel) + request = PdmObject_pb2.PdmParentObjectRequest( + object=self._pb2_object, parent_keyword=class_keyword) + return PdmObject(self._pdm_object_stub.GetAncestorPdmObject(request), + self._channel) def update(self): """Sync all fields from the Python Object to ResInsight""" - self.pdm_object_stub.UpdateExistingPdmObject(self.pb2_object) - -# def createChild(self, child_field, childClassKeyword): -# childRequest = PdmObject_pb2.CreatePdmChildObjectRequest(object=self.pb2Object, child_field=child_field, child_class=childClassKeyword) -# return PdmObject(self.pdmObjectStub.CreateChildPdmObject(childRequest), self.channel) + self._pdm_object_stub.UpdateExistingPdmObject(self._pb2_object) diff --git a/ApplicationCode/GrpcInterface/Python/rips/project.py b/ApplicationCode/GrpcInterface/Python/rips/project.py new file mode 100644 index 0000000000..3aebff0dcf --- /dev/null +++ b/ApplicationCode/GrpcInterface/Python/rips/project.py @@ -0,0 +1,209 @@ +# pylint: disable=too-many-arguments +# pylint: disable=no-member +""" +The ResInsight project module +""" +import grpc + +from rips.case import Case +from rips.gridcasegroup import GridCaseGroup +from rips.pdmobject import PdmObject +from rips.view import View + +import rips.generated.Commands_pb2 as Cmd +from rips.generated.Definitions_pb2 import Empty +import rips.generated.Project_pb2_grpc as Project_pb2_grpc + + +class Project(PdmObject): + """ResInsight project. Not intended to be created separately. + + Automatically created and assigned to Instance. + """ + def __init__(self, channel): + self._project_stub = Project_pb2_grpc.ProjectStub(channel) + PdmObject.__init__(self, self._project_stub.GetPdmObject(Empty()), + channel) + + def open(self, path): + """Open a new project from the given path + + Arguments: + path(str): path to project file + + """ + self._execute_command(openProject=Cmd.FilePathRequest(path=path)) + return self + + def close(self): + """Close the current project (and open new blank project)""" + self._execute_command(closeProject=Empty()) + + def load_case(self, path): + """Load a new case from the given file path + + Arguments: + path(str): file path to case + Returns: + A rips Case object + """ + command_reply = self._execute_command(loadCase=Cmd.FilePathRequest( + path=path)) + return Case(self._channel, command_reply.loadCaseResult.id) + + def selected_cases(self): + """Get a list of all cases selected in the project tree + + Returns: + A list of rips Case objects + """ + case_infos = self._project_stub.GetSelectedCases(Empty()) + cases = [] + for case_info in case_infos.data: + cases.append(Case(self._channel, case_info.id)) + return cases + + def cases(self): + """Get a list of all cases in the project + + Returns: + A list of rips Case objects + """ + try: + case_infos = self._project_stub.GetAllCases(Empty()) + + cases = [] + for case_info in case_infos.data: + cases.append(Case(self._channel, case_info.id)) + return cases + except grpc.RpcError as rpc_error: + if rpc_error.code() == grpc.StatusCode.NOT_FOUND: + return [] + print("ERROR: ", rpc_error) + return [] + + def case(self, case_id): + """Get a specific case from the provided case Id + + Arguments: + id(int): case id + Returns: + A rips Case object + """ + try: + case = Case(self._channel, case_id) + return case + except grpc.RpcError: + return None + + def replace_source_cases(self, grid_list_file, case_group_id=0): + """Replace all source cases within a case group + Arguments: + grid_list_file (str): path to file containing a list of cases + case_group_id (int): id of the case group to replace + """ + return self._execute_command( + replaceSourceCases=Cmd.ReplaceSourceCasesRequest( + gridListFile=grid_list_file, caseGroupId=case_group_id)) + + def create_grid_case_group(self, case_paths): + """Create a Grid Case Group from a list of cases + Arguments: + case_paths (list): list of file path strings + Returns: + A case group id and name + """ + command_reply = self._execute_command( + createGridCaseGroup=Cmd.CreateGridCaseGroupRequest( + casePaths=case_paths)) + return self.grid_case_group( + command_reply.createGridCaseGroupResult.groupId) + + def views(self): + """Get a list of views belonging to a project""" + pdm_objects = self.descendants("ReservoirView") + view_list = [] + for pdm_object in pdm_objects: + view_list.append(View(pdm_object)) + return view_list + + def view(self, view_id): + """Get a particular view belonging to a case by providing view id + Arguments: + id(int): view id + Returns: a view object + """ + views = self.views() + for view_object in views: + if view_object.view_id == view_id: + return view_object + return None + + def grid_case_groups(self): + """Get a list of all grid case groups in the project""" + case_groups = self.descendants("RimIdenticalGridCaseGroup") + + case_group_list = [] + for pdm_group in case_groups: + case_group_list.append(GridCaseGroup(pdm_group)) + return case_group_list + + def grid_case_group(self, group_id): + """Get a particular grid case group belonging to a project + Arguments: + groupId(int): group id + + Returns: a grid case group object + """ + case_groups = self.grid_case_groups() + for case_group in case_groups: + if case_group.group_id == group_id: + return case_group + return None + + def export_multi_case_snapshots(self, grid_list_file): + """Export snapshots for a set of cases + Arguments: + grid_list_file (str): Path to a file containing a list of grids to export snapshot for + """ + return self._execute_command( + exportMultiCaseSnapshot=Cmd.ExportMultiCaseRequest( + gridListFile=grid_list_file)) + + def export_snapshots(self, snapshot_type='ALL', prefix=''): + """ Export all snapshots of a given type + Arguments: + snapshot_type (str): Enum string ('ALL', 'VIEWS' or 'PLOTS') + prefix (str): Exported file name prefix + """ + return self._execute_command( + exportSnapshots=Cmd.ExportSnapshotsRequest( + type=snapshot_type, prefix=prefix, caseId=-1)) + + def export_well_paths(self, well_paths=None, md_step_size=5.0): + """ Export a set of well paths + Arguments: + well_paths(list): List of strings of well paths. If none, export all. + md_step_size(double): resolution of the exported well path + """ + if well_paths is None: + well_paths = [] + elif isinstance(well_paths, str): + well_paths = [well_paths] + return self._execute_command(exportWellPaths=Cmd.ExportWellPathRequest( + wellPathNames=well_paths, mdStepSize=md_step_size)) + + def scale_fracture_template(self, template_id, half_length, height, dfactor, + conductivity): + return self._execute_command( + scaleFractureTemplate=Cmd.ScaleFractureTemplateRequest( + id=template_id, + halfLength=half_length, + height=height, + dFactor=dfactor, + conductivity=conductivity)) + + def set_fracture_containment(self, fracture_id, top_layer, base_layer): + return self._execute_command( + setFractureContainment=Cmd.SetFracContainmentRequest( + id=fracture_id, topLayer=top_layer, baseLayer=base_layer)) diff --git a/ApplicationCode/GrpcInterface/Python/rips/tests/test_cases.py b/ApplicationCode/GrpcInterface/Python/rips/tests/test_cases.py index fc74aa3a47..257ab20fb0 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/tests/test_cases.py +++ b/ApplicationCode/GrpcInterface/Python/rips/tests/test_cases.py @@ -1,6 +1,8 @@ import sys import os import pytest +import grpc +import tempfile sys.path.insert(1, os.path.join(sys.path[0], '../../')) import rips @@ -17,7 +19,7 @@ def test_EmptyProject(rips_instance, initialize_test): def test_OneCase(rips_instance, initialize_test): case = rips_instance.project.load_case(dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID") assert(case.name == "TEST10K_FLT_LGR_NNC") - assert(case.id == 0) + assert(case.case_id == 0) cases = rips_instance.project.cases() assert(len(cases) is 1) @@ -41,7 +43,7 @@ def test_MultipleCases(rips_instance, initialize_test): def test_10k(rips_instance, initialize_test): case_path = dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID" case = rips_instance.project.load_case(path=case_path) - assert(case.grid_count() == 2) + assert(len(case.grids()) == 2) cell_count_info = case.cell_count() assert(cell_count_info.active_cell_count == 11125) assert(cell_count_info.reservoir_cell_count == 316224) @@ -53,17 +55,17 @@ def test_10k(rips_instance, initialize_test): def test_PdmObject(rips_instance, initialize_test): case_path = dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID" case = rips_instance.project.load_case(path=case_path) - assert(case.id == 0) + assert(case.case_id == 0) assert(case.address() is not 0) assert(case.class_keyword() == "EclipseCase") case_id = case.get_value('CaseId') - assert(case_id == case.id) + assert(case_id == case.case_id) @pytest.mark.skipif(sys.platform.startswith('linux'), reason="Brugge is currently exceptionally slow on Linux") def test_brugge_0010(rips_instance, initialize_test): case_path = dataroot.PATH + "/Case_with_10_timesteps/Real10/BRUGGE_0010.EGRID" case = rips_instance.project.load_case(path=case_path) - assert(case.grid_count() == 1) + assert(len(case.grids()) == 1) cellCountInfo = case.cell_count() assert(cellCountInfo.active_cell_count == 43374) assert(cellCountInfo.reservoir_cell_count == 60048) @@ -76,16 +78,36 @@ def test_brugge_0010(rips_instance, initialize_test): def test_replaceCase(rips_instance, initialize_test): project = rips_instance.project.open(dataroot.PATH + "/TEST10K_FLT_LGR_NNC/10KWithWellLog.rsp") case_path = dataroot.PATH + "/Case_with_10_timesteps/Real0/BRUGGE_0000.EGRID" - case = project.case(id=0) + case = project.case(case_id=0) assert(case is not None) assert(case.name == "TEST10K_FLT_LGR_NNC") - assert(case.id == 0) + assert(case.case_id == 0) cases = rips_instance.project.cases() assert(len(cases) is 1) - rips_instance.commands.replace_case(new_grid_file=case_path, case_id=case.id) + case.replace(new_grid_file=case_path) + # Check that the case object has been changed + assert(case.name == "Real0--BRUGGE_0000.EGRID") + assert(case.case_id == 0) + cases = rips_instance.project.cases() assert(len(cases) is 1) - case = project.case(id=0) + # Check that retrieving the case object again will yield the changed object + case = project.case(case_id=0) assert(case.name == "Real0--BRUGGE_0000.EGRID") - assert(case.id == 0) + assert(case.case_id == 0) + +def test_loadNonExistingCase(rips_instance, initialize_test): + case_path = "Nonsense/Nonsense/Nonsense" + with pytest.raises(grpc.RpcError): + assert rips_instance.project.load_case(case_path) + +@pytest.mark.skipif(sys.platform.startswith('linux'), reason="Brugge is currently exceptionally slow on Linux") +def test_exportFlowCharacteristics(rips_instance, initialize_test): + case_path = dataroot.PATH + "/Case_with_10_timesteps/Real0/BRUGGE_0000.EGRID" + case = rips_instance.project.load_case(case_path) + with tempfile.TemporaryDirectory(prefix="rips") as tmpdirname: + print("Temporary folder: ", tmpdirname) + file_name = tmpdirname + "/exportFlowChar.txt" + case.export_flow_characteristics(time_steps=8, producers=[], injectors = "I01", file_name = file_name) + diff --git a/ApplicationCode/GrpcInterface/Python/rips/tests/test_commands.py b/ApplicationCode/GrpcInterface/Python/rips/tests/test_commands.py index 496942f4f8..5fdef57c34 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/tests/test_commands.py +++ b/ApplicationCode/GrpcInterface/Python/rips/tests/test_commands.py @@ -9,50 +9,3 @@ import rips import dataroot -def test_exportSnapshots(rips_instance, initialize_test): - if not rips_instance.is_gui(): - pytest.skip("Cannot run test without a GUI") - - case_path = dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID" - rips_instance.project.load_case(case_path) - with tempfile.TemporaryDirectory(prefix="rips") as tmpdirname: - print("Temporary folder: ", tmpdirname) - rips_instance.commands.set_export_folder(type='SNAPSHOTS', path=tmpdirname) - rips_instance.commands.export_snapshots() - print(os.listdir(tmpdirname)) - assert(len(os.listdir(tmpdirname)) > 0) - for fileName in os.listdir(tmpdirname): - assert(os.path.splitext(fileName)[1] == '.png') - -def test_exportPropertyInView(rips_instance, initialize_test): - case_path = dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID" - rips_instance.project.load_case(case_path) - with tempfile.TemporaryDirectory(prefix="rips") as tmpdirname: - print("Temporary folder: ", tmpdirname) - rips_instance.commands.set_export_folder(type='PROPERTIES', path=tmpdirname) - case = rips_instance.project.case(id=0) - rips_instance.commands.export_property_in_views(0, "3D View", 0) - expected_file_name = case.name + "-" + str("3D_View") + "-" + "T0" + "-SOIL" - full_path = tmpdirname + "/" + expected_file_name - assert(os.path.exists(full_path)) - -@pytest.mark.skipif(sys.platform.startswith('linux'), reason="Brugge is currently exceptionally slow on Linux") -def test_loadGridCaseGroup(rips_instance, initialize_test): - case_paths = [] - case_paths.append(dataroot.PATH + "/Case_with_10_timesteps/Real0/BRUGGE_0000.EGRID") - case_paths.append(dataroot.PATH + "/Case_with_10_timesteps/Real10/BRUGGE_0010.EGRID") - group_id, group_name = rips_instance.commands.create_grid_case_group(case_paths=case_paths) - print(group_id, group_name) - -def test_exportFlowCharacteristics(rips_instance, initialize_test): - case_path = dataroot.PATH + "/Case_with_10_timesteps/Real0/BRUGGE_0000.EGRID" - rips_instance.project.load_case(case_path) - with tempfile.TemporaryDirectory(prefix="rips") as tmpdirname: - print("Temporary folder: ", tmpdirname) - file_name = tmpdirname + "/exportFlowChar.txt" - rips_instance.commands.export_flow_characteristics(case_id=0, time_steps=8, producers=[], injectors = "I01", file_name = file_name) - -def test_loadNonExistingCase(rips_instance, initialize_test): - case_path = "Nonsense/Nonsense/Nonsense" - with pytest.raises(grpc.RpcError): - assert rips_instance.project.load_case(case_path) diff --git a/ApplicationCode/GrpcInterface/Python/rips/tests/test_grids.py b/ApplicationCode/GrpcInterface/Python/rips/tests/test_grids.py index 918e37b537..80ad582d16 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/tests/test_grids.py +++ b/ApplicationCode/GrpcInterface/Python/rips/tests/test_grids.py @@ -9,7 +9,7 @@ import dataroot def test_10k(rips_instance, initialize_test): casePath = dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID" case = rips_instance.project.load_case(path=casePath) - assert(case.grid_count() == 2) + assert(len(case.grids()) == 2) grid = case.grid(index=0) dimensions = grid.dimensions() assert(dimensions.i == 90) diff --git a/ApplicationCode/GrpcInterface/Python/rips/tests/test_project.py b/ApplicationCode/GrpcInterface/Python/rips/tests/test_project.py index 444ed41a43..592142bd0a 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/tests/test_project.py +++ b/ApplicationCode/GrpcInterface/Python/rips/tests/test_project.py @@ -1,6 +1,8 @@ import sys import os -import pytest +import pytest +import grpc +import tempfile sys.path.insert(1, os.path.join(sys.path[0], '../../')) import rips @@ -9,9 +11,32 @@ import dataroot def test_loadProject(rips_instance, initialize_test): project = rips_instance.project.open(dataroot.PATH + "/TEST10K_FLT_LGR_NNC/10KWithWellLog.rsp") - case = project.case(id=0) + case = project.case(case_id=0) assert(case is not None) assert(case.name == "TEST10K_FLT_LGR_NNC") - assert(case.id == 0) + assert(case.case_id == 0) cases = rips_instance.project.cases() - assert(len(cases) is 1) \ No newline at end of file + assert(len(cases) is 1) + +@pytest.mark.skipif(sys.platform.startswith('linux'), reason="Brugge is currently exceptionally slow on Linux") +def test_loadGridCaseGroup(rips_instance, initialize_test): + case_paths = [] + case_paths.append(dataroot.PATH + "/Case_with_10_timesteps/Real0/BRUGGE_0000.EGRID") + case_paths.append(dataroot.PATH + "/Case_with_10_timesteps/Real10/BRUGGE_0010.EGRID") + grid_case_group = rips_instance.project.create_grid_case_group(case_paths=case_paths) + assert(grid_case_group is not None and grid_case_group.group_id == 0) + +def test_exportSnapshots(rips_instance, initialize_test): + if not rips_instance.is_gui(): + pytest.skip("Cannot run test without a GUI") + + case_path = dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID" + rips_instance.project.load_case(case_path) + with tempfile.TemporaryDirectory(prefix="rips") as tmpdirname: + print("Temporary folder: ", tmpdirname) + rips_instance.set_export_folder(export_type='SNAPSHOTS', path=tmpdirname) + rips_instance.project.export_snapshots() + print(os.listdir(tmpdirname)) + assert(len(os.listdir(tmpdirname)) > 0) + for fileName in os.listdir(tmpdirname): + assert(os.path.splitext(fileName)[1] == '.png') diff --git a/ApplicationCode/GrpcInterface/Python/rips/tests/test_properties.py b/ApplicationCode/GrpcInterface/Python/rips/tests/test_properties.py index 7ba6c08340..1c197bbe92 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/tests/test_properties.py +++ b/ApplicationCode/GrpcInterface/Python/rips/tests/test_properties.py @@ -2,6 +2,7 @@ import sys import os import grpc import pytest +import tempfile sys.path.insert(1, os.path.join(sys.path[0], '../../')) import rips @@ -12,7 +13,7 @@ def test_10kAsync(rips_instance, initialize_test): casePath = dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID" case = rips_instance.project.load_case(path=casePath) - resultChunks = case.properties.active_cell_property_async('DYNAMIC_NATIVE', 'SOIL', 1) + resultChunks = case.active_cell_property_async('DYNAMIC_NATIVE', 'SOIL', 1) mysum = 0.0 count = 0 for chunk in resultChunks: @@ -27,7 +28,7 @@ def test_10kSync(rips_instance, initialize_test): casePath = dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID" case = rips_instance.project.load_case(path=casePath) - results = case.properties.active_cell_property('DYNAMIC_NATIVE', 'SOIL', 1) + results = case.active_cell_property('DYNAMIC_NATIVE', 'SOIL', 1) mysum = sum(results) average = mysum / len(results) assert(mysum == pytest.approx(621.768, abs=0.001)) @@ -38,27 +39,27 @@ def test_10k_set(rips_instance, initialize_test): casePath = dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID" case = rips_instance.project.load_case(path=casePath) - results = case.properties.active_cell_property('DYNAMIC_NATIVE', 'SOIL', 1) - case.properties.set_active_cell_property(results, 'GENERATED', 'SOIL', 1) + results = case.active_cell_property('DYNAMIC_NATIVE', 'SOIL', 1) + case.set_active_cell_property(results, 'GENERATED', 'SOIL', 1) def test_10k_set_out_of_bounds(rips_instance, initialize_test): casePath = dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID" case = rips_instance.project.load_case(path=casePath) - results = case.properties.active_cell_property('DYNAMIC_NATIVE', 'SOIL', 1) + results = case.active_cell_property('DYNAMIC_NATIVE', 'SOIL', 1) results.append(5.0) with pytest.raises(grpc.RpcError): - assert case.properties.set_active_cell_property(results, 'GENERATED', 'SOIL', 1) + assert case.set_active_cell_property(results, 'GENERATED', 'SOIL', 1) def test_10k_set_out_of_bounds_client(rips_instance, initialize_test): casePath = dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID" case = rips_instance.project.load_case(path=casePath) - results = case.properties.active_cell_property('DYNAMIC_NATIVE', 'SOIL', 1) - case.properties.chunk_size = len(results) + results = case.active_cell_property('DYNAMIC_NATIVE', 'SOIL', 1) + case.chunk_size = len(results) results.append(5.0) with pytest.raises(IndexError): - assert case.properties.set_active_cell_property(results, 'GENERATED', 'SOIL', 1) + assert case.set_active_cell_property(results, 'GENERATED', 'SOIL', 1) def createResult(poroChunks, permxChunks): for (poroChunk, permxChunk) in zip(poroChunks, permxChunks): @@ -76,16 +77,26 @@ def test_10k_PoroPermX(rips_instance, initialize_test): casePath = dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID" case = rips_instance.project.load_case(path=casePath) - poroChunks = case.properties.active_cell_property_async('STATIC_NATIVE', 'PORO', 0) - permxChunks = case.properties.active_cell_property_async('STATIC_NATIVE', 'PERMX', 0) + poroChunks = case.active_cell_property_async('STATIC_NATIVE', 'PORO', 0) + permxChunks = case.active_cell_property_async('STATIC_NATIVE', 'PERMX', 0) - case.properties.set_active_cell_property_async(createResult(poroChunks, permxChunks), 'GENERATED', 'POROPERMXAS', 0) + case.set_active_cell_property_async(createResult(poroChunks, permxChunks), 'GENERATED', 'POROPERMXAS', 0) - poro = case.properties.active_cell_property('STATIC_NATIVE', 'PORO', 0) - permx = case.properties.active_cell_property('STATIC_NATIVE', 'PERMX', 0) - poroPermX = case.properties.active_cell_property('GENERATED', 'POROPERMXAS', 0) + poro = case.active_cell_property('STATIC_NATIVE', 'PORO', 0) + permx = case.active_cell_property('STATIC_NATIVE', 'PERMX', 0) + poroPermX = case.active_cell_property('GENERATED', 'POROPERMXAS', 0) checkResults(poro, permx, poroPermX) - - \ No newline at end of file +def test_exportPropertyInView(rips_instance, initialize_test): + case_path = dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID" + rips_instance.project.load_case(case_path) + with tempfile.TemporaryDirectory(prefix="rips") as tmpdirname: + print("Temporary folder: ", tmpdirname) + rips_instance.set_export_folder(export_type='PROPERTIES', path=tmpdirname) + case = rips_instance.project.case(case_id=0) + view = case.view(view_id=0) + view.export_property() + expected_file_name = case.name + "-" + str("3D_View") + "-" + "T0" + "-SOIL" + full_path = tmpdirname + "/" + expected_file_name + assert(os.path.exists(full_path)) \ No newline at end of file diff --git a/ApplicationCode/GrpcInterface/Python/rips/View.py b/ApplicationCode/GrpcInterface/Python/rips/view.py similarity index 50% rename from ApplicationCode/GrpcInterface/Python/rips/View.py rename to ApplicationCode/GrpcInterface/Python/rips/view.py index 504d1387dc..99f30aa38f 100644 --- a/ApplicationCode/GrpcInterface/Python/rips/View.py +++ b/ApplicationCode/GrpcInterface/Python/rips/view.py @@ -1,8 +1,13 @@ -import rips.Case # Circular import of Case, which already imports View. Use full name. -from rips.Commands import Commands -from rips.PdmObject import PdmObject +""" +ResInsight 3d view module +""" +import rips.generated.Commands_pb2 as Cmd -class View (PdmObject): +import rips.case # Circular import of Case, which already imports View. Use full name. +from rips.pdmobject import PdmObject + + +class View(PdmObject): """ResInsight view class Attributes: @@ -10,9 +15,9 @@ class View (PdmObject): """ def __init__(self, pdm_object): - self.id = pdm_object.get_value("ViewId") + self.view_id = pdm_object.get_value("ViewId") - PdmObject.__init__(self, pdm_object.pb2_object, pdm_object.channel) + PdmObject.__init__(self, pdm_object._pb2_object, pdm_object._channel) def show_grid_box(self): """Check if the grid box is meant to be shown in the view""" @@ -36,7 +41,7 @@ class View (PdmObject): def apply_cell_result(self, result_type, result_variable): """Apply a regular cell result - + Arguments: result_type (str): String representing the result category. The valid values are - DYNAMIC_NATIVE @@ -54,11 +59,12 @@ class View (PdmObject): cell_result.set_value("ResultVariable", result_variable) cell_result.update() - def apply_flow_diagnostics_cell_result(self, - result_variable = 'TOF', - selection_mode = 'FLOW_TR_BY_SELECTION', - injectors = [], - producers = []): + def apply_flow_diagnostics_cell_result( + self, + result_variable='TOF', + selection_mode='FLOW_TR_BY_SELECTION', + injectors=None, + producers=None): """Apply a flow diagnostics cell result Arguments: @@ -66,7 +72,7 @@ class View (PdmObject): The valid values are 'TOF', 'Fraction', 'MaxFractionTracer' and 'Communication'. selection_mode (str): String specifying which tracers to select. The valid values are - - FLOW_TR_INJ_AND_PROD (all injector and producer tracers), + - FLOW_TR_INJ_AND_PROD (all injector and producer tracers), - FLOW_TR_PRODUCERS (all producers) - FLOW_TR_INJECTORS (all injectors), - FLOW_TR_BY_SELECTION (specify individual tracers in the @@ -76,6 +82,10 @@ class View (PdmObject): producers (list): List of producer tracers (strings) to select. Requires selection_mode to be 'FLOW_TR_BY_SELECTION'. """ + if injectors is None: + injectors = [] + if producers is None: + producers = [] cell_result = self.set_cell_result() cell_result.set_value("ResultType", "FLOW_DIAGNOSTICS") cell_result.set_value("ResultVariable", result_variable) @@ -92,9 +102,69 @@ class View (PdmObject): pdm_case = self.ancestor("ResInsightGeoMechCase") if pdm_case is None: return None - return rips.Case(self.channel, pdm_case.get_value("CaseId")) + return rips.case.Case(self._channel, pdm_case.get_value("CaseId")) def clone(self): """Clone the current view""" - view_id = Commands(self.channel).clone_view(self.id) + view_id = self._execute_command(cloneView=Cmd.CloneViewRequest( + viewId=self.view_id)).createViewResult.viewId return self.case().view(view_id) + + def set_time_step(self, time_step): + case_id = self.case().case_id + return self._execute_command(setTimeStep=Cmd.SetTimeStepParams( + caseId=case_id, viewId=self.view_id, timeStep=time_step)) + + def export_sim_well_fracture_completions(self, time_step, + simulation_well_names, file_split, + compdat_export): + if isinstance(simulation_well_names, str): + simulation_well_names = [simulation_well_names] + + case_id = self.case().case_id + return self._execute_command( + exportSimWellFractureCompletions=Cmd.ExportSimWellPathFracRequest( + caseId=case_id, + viewId=self.view_id, + timeStep=time_step, + simulationWellNames=simulation_well_names, + fileSplit=file_split, + compdatExport=compdat_export)) + + def export_visible_cells(self, + export_keyword='FLUXNUM', + visible_active_cells_value=1, + hidden_active_cells_value=0, + inactive_cells_value=0): + case_id = self.case().case_id + return self._execute_command( + exportVisibleCells=Cmd.ExportVisibleCellsRequest( + caseId=case_id, + viewId=self.view_id, + exportKeyword=export_keyword, + visibleActiveCellsValue=visible_active_cells_value, + hiddenActiveCellsValue=hidden_active_cells_value, + inactiveCellsValue=inactive_cells_value)) + + def export_property(self, undefined_value=0.0): + """ Export the current Eclipse property from the view + + Arguments: + undefined_value (double): Value to use for undefined values. Defaults to 0.0 + """ + case_id = self.case().case_id + return self._execute_command( + exportPropertyInViews=Cmd.ExportPropertyInViewsRequest( + caseId=case_id, + viewIds=[self.view_id], + undefinedValue=undefined_value)) + + def export_snapshot(self, prefix=''): + """ Export snapshot for the current view + Arguments: + prefix (str): Exported file name prefix + """ + case_id = self.case().case_id + return self._execute_command( + exportSnapshots=Cmd.ExportSnapshotsRequest( + type='VIEWS', prefix=prefix, caseId=case_id, viewId=self.view_id)) diff --git a/ApplicationCode/UserInterface/RiuMainWindow.cpp b/ApplicationCode/UserInterface/RiuMainWindow.cpp index 151f644e77..00be1aa1dd 100644 --- a/ApplicationCode/UserInterface/RiuMainWindow.cpp +++ b/ApplicationCode/UserInterface/RiuMainWindow.cpp @@ -1506,7 +1506,7 @@ void RiuMainWindow::slotSnapshotAllViewsToFile() // Save images in snapshot catalog relative to project directory QString absolutePathToSnapshotDir = app->createAbsolutePathFromProjectRelativePath( "snapshots" ); - RicSnapshotAllViewsToFileFeature::exportSnapshotOfAllViewsIntoFolder( absolutePathToSnapshotDir ); + RicSnapshotAllViewsToFileFeature::exportSnapshotOfViewsIntoFolder( absolutePathToSnapshotDir ); } //--------------------------------------------------------------------------------------------------