Move GrpcInterface into top level

This commit is contained in:
Gaute Lindkvist
2021-01-06 14:57:14 +01:00
parent 81699db187
commit 2de5c9ce0b
113 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,335 @@
cmake_minimum_required(VERSION 3.12)
project(GrpcInterface)
message(STATUS "GRPC enabled")
add_definitions(-DENABLE_GRPC)
if(VCPKG_AUTO_INSTALL)
vcpkg_install(grpc)
endif()
set(CMAKE_UNITY_BUILD false)
set(RESINSIGHT_GRPC_PYTHON_EXECUTABLE
""
CACHE
FILEPATH
"gRPC : Path to Python 3 executable, required to build the Python client library"
)
if(MSVC)
add_definitions(-D_WIN32_WINNT=0x600)
endif()
add_definitions(-D_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING)
set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcServer.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcHelper.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCallbacks.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCallbacks.inl
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcServiceInterface.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCaseService.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcSimulationWellService.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcGridService.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcProjectService.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCommandService.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcAppService.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcPropertiesService.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcNNCPropertiesService.h
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcPdmObjectService.h)
set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcServer.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcHelper.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcServiceInterface.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCaseService.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcSimulationWellService.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcGridService.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcProjectService.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcCommandService.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcAppService.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcPropertiesService.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcNNCPropertiesService.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcPdmObjectService.cpp)
# Find Protobuf installation Looks for protobuf-config.cmake file installed by
# Protobuf's cmake installation.
set(protobuf_MODULE_COMPATIBLE ON)
find_package(Protobuf CONFIG 3.0 QUIET)
if(Protobuf_FOUND)
message(STATUS "Using protobuf ${protobuf_VERSION}")
# Find gRPC installation Looks for gRPCConfig.cmake file installed by gRPC's
# cmake installation.
find_package(gRPC CONFIG REQUIRED)
message(STATUS "Using gRPC ${gRPC_VERSION}")
set(_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf)
set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>)
set(_GRPC_GRPCPP_UNSECURE gRPC::grpc++_unsecure gRPC::grpc_unsecure gRPC::gpr)
set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>)
set(GRPC_LIBRARIES ${_GRPC_GRPCPP_UNSECURE} ${_PROTOBUF_LIBPROTOBUF})
set_target_properties(
${GRPC_LIBRARIES} PROPERTIES MAP_IMPORTED_CONFIG_MINSIZEREL RELEASE
MAP_IMPORTED_CONFIG_RELWITHDEBINFO RELEASE)
set(RESINSIGHT_GRPC_LIBRARIES ${GRPC_LIBRARIES} PARENT_SCOPE)
else()
message(STATUS "Using RESINSIGHT_GRPC_INSTALL_PREFIX=${RESINSIGHT_GRPC_INSTALL_PREFIX}")
set(RESINSIGHT_GRPC_INSTALL_PREFIX
""
CACHE PATH "gRPC : Install prefix for gRPC")
if(NOT DEFINED RESINSIGHT_GRPC_INSTALL_PREFIX
OR NOT EXISTS ${RESINSIGHT_GRPC_INSTALL_PREFIX})
message(
FATAL_ERROR
"You need a valid RESINSIGHT_GRPC_INSTALL_PREFIX set to build with gRPC"
)
endif()
set(ENV{PKG_CONFIG_PATH} "${RESINSIGHT_GRPC_INSTALL_PREFIX}/lib/pkgconfig")
find_package(PkgConfig REQUIRED)
pkg_check_modules(GRPC REQUIRED grpc grpc++_unsecure>=1.20 grpc_unsecure gpr
protobuf libcares)
if(EXISTS "${RESINSIGHT_GRPC_INSTALL_PREFIX}/bin/protoc")
set(_PROTOBUF_PROTOC "${RESINSIGHT_GRPC_INSTALL_PREFIX}/bin/protoc")
elseif(EXISTS "${RESINSIGHT_GRPC_INSTALL_PREFIX}/tools/protobuf/protoc")
set(_PROTOBUF_PROTOC
"${RESINSIGHT_GRPC_INSTALL_PREFIX}/tools/protobuf/protoc")
else()
message(FATAL_ERROR "Could not find the protobuf compiler (protoc)")
endif()
if(EXISTS "${RESINSIGHT_GRPC_INSTALL_PREFIX}/bin/grpc_cpp_plugin")
set(_GRPC_CPP_PLUGIN_EXECUTABLE
"${RESINSIGHT_GRPC_INSTALL_PREFIX}/bin/grpc_cpp_plugin")
elseif(EXISTS "${RESINSIGHT_GRPC_INSTALL_PREFIX}/tools/grpc/grpc_cpp_plugin")
set(_GRPC_CPP_PLUGIN_EXECUTABLE
"${RESINSIGHT_GRPC_INSTALL_PREFIX}/tools/grpc/grpc_cpp_plugin")
endif()
include_directories(AFTER ${GRPC_INCLUDE_DIRS})
set(RESINSIGHT_GRPC_LIBRARIES ${GRPC_LINK_LIBRARIES} PARENT_SCOPE)
#list(APPEND RESINSIGHT_GRPC_LIBRARIES upb)
endif()
set(_LINK_LIBRARIES
${QT_LIBRARIES}
LibCore
cafCommand
cafPdmCvf
cafPdmScripting
cafTensor
cafViewer
cafVizExtensions
ecl
nightcharts
qwt)
# Proto files
set(PROTO_FILES
"Definitions"
"PdmObject"
"Case"
"SimulationWell"
"Project"
"Commands"
"NNCProperties"
"App"
"Properties"
"Grid")
set(GRPC_PYTHON_SOURCE_PATH "${CMAKE_CURRENT_LIST_DIR}/Python")
add_custom_target(PipInstall)
foreach(proto_file ${PROTO_FILES})
get_filename_component(
rips_proto "${CMAKE_CURRENT_LIST_DIR}/GrpcProtos/${proto_file}.proto"
ABSOLUTE)
get_filename_component(rips_proto_path "${rips_proto}" PATH)
list(APPEND GRPC_PROTO_FILES_FULL_PATH ${rips_proto})
set(rips_proto_srcs "${CMAKE_BINARY_DIR}/Generated/${proto_file}.pb.cc")
set(rips_proto_hdrs "${CMAKE_BINARY_DIR}/Generated/${proto_file}.pb.h")
set(rips_grpc_srcs "${CMAKE_BINARY_DIR}/Generated/${proto_file}.grpc.pb.cc")
set(rips_grpc_hdrs "${CMAKE_BINARY_DIR}/Generated/${proto_file}.grpc.pb.h")
add_custom_command(
OUTPUT "${rips_proto_srcs}" "${rips_proto_hdrs}" "${rips_grpc_srcs}"
"${rips_grpc_hdrs}"
COMMAND
${_PROTOBUF_PROTOC} ARGS --grpc_out "${CMAKE_BINARY_DIR}/Generated"
--cpp_out "${CMAKE_BINARY_DIR}/Generated" -I "${rips_proto_path}"
--plugin=protoc-gen-grpc="${_GRPC_CPP_PLUGIN_EXECUTABLE}" "${rips_proto}"
DEPENDS "${rips_proto}")
set(rips_proto_python "rips/generated/${proto_file}_pb2.py")
set(rips_grpc_python "rips/generated/${proto_file}_pb2_grpc.py")
if(RESINSIGHT_GRPC_PYTHON_EXECUTABLE)
message(
STATUS "Using Python Executable: ${RESINSIGHT_GRPC_PYTHON_EXECUTABLE}")
add_custom_command(
OUTPUT "${GRPC_PYTHON_SOURCE_PATH}/${rips_proto_python}"
"${GRPC_PYTHON_SOURCE_PATH}/${rips_grpc_python}"
COMMAND
${RESINSIGHT_GRPC_PYTHON_EXECUTABLE} ARGS -m grpc_tools.protoc -I
"${rips_proto_path}" --python_out
"${GRPC_PYTHON_SOURCE_PATH}/rips/generated" --grpc_python_out
"${GRPC_PYTHON_SOURCE_PATH}/rips/generated" "${rips_proto}"
DEPENDS "${rips_proto}"
COMMENT "Generating ${rips_proto_python} and ${rips_grpc_python}"
VERBATIM)
list(APPEND GRPC_PYTHON_GENERATED_SOURCES ${rips_proto_python}
${rips_grpc_python})
else()
message(
STATUS
"RESINSIGHT_GRPC_PYTHON_EXECUTABLE not specified. Will not install Python client code"
)
endif()
list(APPEND GRPC_HEADER_FILES ${rips_proto_hdrs} ${rips_grpc_hdrs})
list(APPEND GRPC_CPP_SOURCES ${rips_proto_srcs} ${rips_grpc_srcs})
endforeach(proto_file)
if(RESINSIGHT_GRPC_PYTHON_EXECUTABLE)
configure_file(${CMAKE_SOURCE_DIR}/ApplicationCode/Adm/RiaVersionInfo.py.cmake
${GRPC_PYTHON_SOURCE_PATH}/rips/generated/RiaVersionInfo.py)
configure_file(${GRPC_PYTHON_SOURCE_PATH}/setup.py.cmake
${GRPC_PYTHON_SOURCE_PATH}/setup.py)
endif()
list(
APPEND
GRPC_PYTHON_SOURCES
"rips/generated/RiaVersionInfo.py"
"rips/__init__.py"
"rips/case.py"
"rips/contour_map.py"
"rips/grid.py"
"rips/gridcasegroup.py"
"rips/instance.py"
"rips/pdmobject.py"
"rips/plot.py"
"rips/project.py"
"rips/simulation_well.py"
"rips/view.py"
"rips/well_log_plot.py"
"rips/PythonExamples/instance_example.py"
"rips/PythonExamples/command_example.py"
"rips/PythonExamples/case_grid_group.py"
"rips/PythonExamples/case_info_streaming_example.py"
"rips/PythonExamples/create_wbs_plot.py"
"rips/PythonExamples/export_plots.py"
"rips/PythonExamples/export_snapshots.py"
"rips/PythonExamples/error_handling.py"
"rips/PythonExamples/import_well_paths_and_logs.py"
"rips/PythonExamples/soil_porv_async.py"
"rips/PythonExamples/soil_porv_sync.py"
"rips/PythonExamples/selected_cases.py"
"rips/PythonExamples/all_cases.py"
"rips/PythonExamples/replace_case.py"
"rips/PythonExamples/set_grid_properties.py"
"rips/PythonExamples/set_cell_result.py"
"rips/PythonExamples/set_flow_diagnostics_result.py"
"rips/PythonExamples/grid_information.py"
"rips/PythonExamples/input_prop_test_sync.py"
"rips/PythonExamples/input_prop_test_async.py"
"rips/PythonExamples/soil_average_async.py"
"rips/PythonExamples/soil_average_sync.py"
"rips/PythonExamples/view_example.py"
"rips/tests/test_cases.py"
"rips/tests/test_grids.py"
"rips/tests/test_properties.py"
"rips/tests/test_project.py"
"rips/tests/conftest.py"
"rips/tests/dataroot.py"
"rips/tests/test_nnc_properties.py"
"rips/tests/test_simulation_wells.py"
"rips/tests/test_summary_cases.py"
"rips/tests/test_wells.py"
"requirements.txt"
"setup.py"
"README.md"
"LICENSE")
list(APPEND GRPC_PYTHON_SOURCES ${GRPC_PYTHON_GENERATED_SOURCES})
if(RESINSIGHT_GRPC_PYTHON_EXECUTABLE)
foreach(PYTHON_SCRIPT ${GRPC_PYTHON_SOURCES})
list(APPEND GRPC_PYTHON_SOURCES_FULL_PATH
"${GRPC_PYTHON_SOURCE_PATH}/${PYTHON_SCRIPT}")
endforeach()
endif()
add_library(
${PROJECT_NAME} OBJECT
${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES}
${GRPC_HEADER_FILES} ${GRPC_CPP_SOURCES})
target_include_directories(${PROJECT_NAME} PUBLIC ${GRPC_INCLUDE_DIRS})
target_link_directories(${PROJECT_NAME} PUBLIC ${GRPC_LIBRARY_DIRS})
target_link_libraries(${PROJECT_NAME} PUBLIC ${_LINK_LIBRARIES})
if(MSVC)
# GRPC generates a lot of harmless warnings on MSVC
set_target_properties(
${PROJECT_NAME}
PROPERTIES COMPILE_FLAGS "/wd4251 /wd4702 /wd4005 /wd4244 /wd4125 /wd4267")
else()
set_target_properties(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS
"-Wno-overloaded-virtual")
endif()
# install gRPC Python files
if(RESINSIGHT_GRPC_PYTHON_EXECUTABLE AND RESINSIGHT_GRPC_DOWNLOAD_PYTHON_MODULE)
message(STATUS "Installing Python modules")
add_custom_command(
TARGET PipInstall
COMMAND ${RESINSIGHT_GRPC_PYTHON_EXECUTABLE} ARGS -m pip install --user
wheel setuptools pytest
COMMAND ${RESINSIGHT_GRPC_PYTHON_EXECUTABLE} ARGS -m pip install --user
grpcio-tools)
endif()
if(RESINSIGHT_GRPC_PYTHON_EXECUTABLE AND RESINSIGHT_GRPC_BUNDLE_PYTHON_MODULE)
message(STATUS "Bundling Python GRPC modules")
add_custom_command(
TARGET PipInstall
COMMAND ${RESINSIGHT_GRPC_PYTHON_EXECUTABLE} ARGS -m pip install --user
--target=${GRPC_PYTHON_SOURCE_PATH} grpcio-tools)
endif()
if(RESINSIGHT_GRPC_PYTHON_EXECUTABLE)
add_custom_target(GeneratedPythonSources ALL
DEPENDS ${GRPC_PYTHON_SOURCES_FULL_PATH})
add_dependencies(${PROJECT_NAME} GeneratedPythonSources)
if(RESINSIGHT_GRPC_DOWNLOAD_PYTHON_MODULE)
add_dependencies(${PROJECT_NAME} PipInstall)
add_dependencies(GeneratedPythonSources PipInstall)
endif()
endif()
if(RESINSIGHT_GRPC_PYTHON_EXECUTABLE)
install(DIRECTORY ${GRPC_PYTHON_SOURCE_PATH}/
DESTINATION ${RESINSIGHT_INSTALL_FOLDER}/Python)
endif()
source_group(
"GrpcInterface"
FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES}
${CMAKE_CURRENT_LIST_DIR}/CMakeLists.cmake)
source_group("GrpcInterface\\GrpcProtos" FILES ${GRPC_PROTO_FILES_FULL_PATH})
if(RESINSIGHT_GRPC_PYTHON_EXECUTABLE)
source_group(
TREE ${GRPC_PYTHON_SOURCE_PATH}
FILES ${GRPC_PYTHON_SOURCES_FULL_PATH}
PREFIX "GrpcInterface\\Python")
endif()

View File

@@ -0,0 +1,28 @@
syntax = "proto3";
package rips;
import "Definitions.proto";
service App {
rpc GetVersion(Empty) returns (Version) {}
rpc Exit(Empty) returns (Empty) {}
rpc GetRuntimeInfo(Empty) returns (RuntimeInfo) {}
}
message Version {
int32 major_version = 1;
int32 minor_version = 2;
int32 patch_version = 3;
}
enum ApplicationTypeEnum
{
GUI_APPLICATION = 0;
CONSOLE_APPLICATION = 1;
}
message RuntimeInfo
{
ApplicationTypeEnum app_type = 1;
}

View File

@@ -0,0 +1,140 @@
syntax = "proto3";
import "PdmObject.proto";
import "Definitions.proto";
package rips;
service Case
{
rpc GetGridCount(CaseRequest) returns(GridCount) {}
rpc GetCellCount(CellInfoRequest) returns (CellCount) {}
rpc GetCellInfoForActiveCells(CellInfoRequest) returns (stream CellInfoArray) {}
rpc GetCellCenterForActiveCells(CellInfoRequest) returns (stream CellCenters) {}
rpc GetCellCornersForActiveCells(CellInfoRequest) returns (stream CellCornersArray) {}
rpc GetCoarseningInfoArray(CaseRequest) returns (CoarseningInfoArray) {}
rpc GetTimeSteps(CaseRequest) returns (TimeStepDates) {}
rpc GetSelectedCells(CaseRequest) returns (stream SelectedCells) {}
rpc GetDaysSinceStart(CaseRequest) returns (DaysSinceStart) {}
rpc GetCaseInfo(CaseRequest) returns (CaseInfo) {}
rpc GetPdmObject(CaseRequest) returns (PdmObject) {}
rpc GetReservoirBoundingBox(CaseRequest) returns (BoundingBox) {}
}
message CaseRequest {
int32 id = 1;
}
message CaseInfo
{
int32 id = 1;
int32 group_id = 2;
string name = 3;
string type = 4;
}
message CaseInfoArray
{
repeated CaseInfo data = 1;
}
message BoundingBox
{
double min_x = 1;
double max_x = 2;
double min_y = 3;
double max_y = 4;
double min_z = 5;
double max_z = 6;
}
message CaseGroup
{
int32 id = 1;
string name = 2;
}
message CaseGroups
{
repeated CaseGroup case_groups = 1;
}
message GridCount
{
int32 count = 1;
}
message CellCount
{
int32 active_cell_count = 1;
int32 reservoir_cell_count = 2;
}
enum PorosityModelType
{
MATRIX_MODEL = 0;
FRACTURE_MODEL = 1;
}
message CellInfoRequest
{
CaseRequest case_request = 1;
PorosityModelType porosity_model = 2;
}
message CellInfoArray
{
repeated CellInfo data = 1;
}
message CellInfo
{
int32 grid_index = 1;
int32 parent_grid_index = 2;
int32 coarsening_box_index = 3;
Vec3i local_ijk = 4;
Vec3i parent_ijk = 5;
}
message CoarseningInfoArray
{
repeated CoarseningInfo data = 1;
}
message CoarseningInfo
{
Vec3i min = 1;
Vec3i max = 2;
}
message TimeStepDates
{
repeated TimeStepDate dates = 1;
}
message TimeStepDate
{
int32 year = 1;
int32 month = 2;
int32 day = 3;
int32 hour = 4;
int32 minute = 5;
int32 second = 6;
}
message DaysSinceStart
{
repeated double day_decimals = 1;
}
message SelectedCell
{
int32 grid_index = 1;
Vec3i ijk = 2;
}
message SelectedCells
{
repeated SelectedCell cells = 1;
}

View File

@@ -0,0 +1,447 @@
syntax = "proto3";
import "Case.proto";
import "Definitions.proto";
import "PdmObject.proto";
package rips;
/*
* The Commands service handles generic ResInsight RicfCommandObject-commands
* The CommandParams is used to deduce command name from the chosen oneof-message
* .. and the parameters are in the oneof-message itself.
* Note that we several times duplicate nearly the same message. This is because
* it is not recommended to reuse existing messages for different purposes.
*/
service Commands
{
rpc Execute(CommandParams) returns(CommandReply) {}
}
message FilePathRequest
{
string path = 1;
}
message ReplaceCaseRequest
{
string newGridFile = 1;
int32 caseId = 2;
}
message ReplaceCaseRequests
{
repeated ReplaceCaseRequest casePairs = 1;
}
message ReplaceSourceCasesRequest
{
string gridListFile = 1;
int32 caseGroupId = 2;
}
message ExportMultiCaseRequest
{
string gridListFile = 1;
}
enum PlotOutputFormat
{
PNG = 0;
PDF = 1;
}
enum SnapshotType
{
VIEWS = 0;
PLOTS = 1;
ALL = 2;
}
message ExportSnapshotsRequest
{
SnapshotType type = 1;
string prefix = 2;
int32 caseId = 3;
int32 viewId = 4;
string exportFolder = 5;
PlotOutputFormat plotOutputFormat = 6;
}
message ExportPropertyRequest
{
int32 caseId = 1;
int32 timeStep = 2;
string property = 3;
string eclipseKeyword = 4;
double undefinedValue = 5;
string exportFile = 6;
}
message ExportPropertyInViewsRequest
{
int32 caseId = 1;
repeated int32 viewIds = 2;
double undefinedValue = 3;
}
enum CompdatExportSplit
{
UNIFIED_FILE = 0;
SPLIT_ON_WELL = 1;
SPLIT_ON_WELL_AND_COMPLETION_TYPE = 2;
}
enum CompdatExportType
{
TRANSMISSIBILITIES = 0;
WPIMULT_AND_DEFAULT_CONNECTION_FACTORS = 1;
NO_COMPLETIONS = 2;
}
enum CompdatCombinationMode
{
INDIVIDUALLY = 0;
COMBINED = 1;
}
message ExportWellPathCompRequest
{
int32 caseId = 1;
int32 timeStep = 2;
repeated string wellPathNames = 3;
CompdatExportSplit fileSplit = 4;
CompdatExportType compdatExport = 5;
bool includePerforations = 6;
bool includeFishbones = 7;
bool excludeMainBoreForFishbones = 8;
CompdatCombinationMode combinationMode = 9;
}
message ExportSimWellPathFracRequest
{
int32 caseId = 1;
int32 viewId = 2;
int32 timeStep = 3;
repeated string simulationWellNames = 4;
CompdatExportSplit fileSplit = 5;
CompdatExportType compdatExport = 6;
}
message ExportMswRequest
{
int32 caseId = 1;
string wellPath = 2;
}
message ExportWellPathRequest
{
repeated string wellPathNames = 1;
double mdStepSize = 2;
}
message ExportVisibleCellsRequest
{
int32 caseId = 1;
int32 viewId = 2;
string exportKeyword = 3;
int32 visibleActiveCellsValue = 4;
int32 hiddenActiveCellsValue = 5;
int32 inactiveCellsValue = 6;
}
enum ExportFolderType {
COMPLETIONS = 0;
SNAPSHOTS = 1;
PROPERTIES = 2;
STATISTICS = 3;
WELLPATHS = 4;
CELLS = 5;
LGRS = 6;
}
message SetExportFolderRequest
{
ExportFolderType type = 1;
string path = 2;
bool createFolder = 3;
}
message RunOctaveScriptRequest
{
string path = 1;
repeated int32 caseIds = 2;
}
message SetWindowSizeParams
{
int32 height = 1;
int32 width = 2;
}
message ComputeCaseGroupStatRequest
{
repeated int32 caseIds = 1;
int32 caseGroupId = 2;
}
message SetTimeStepParams
{
int32 caseId = 1;
int32 viewId = 2;
int32 timeStep = 3;
}
message ScaleFractureTemplateRequest
{
int32 id = 1;
double halfLength = 2;
double height = 3;
}
message SetFracContainmentRequest
{
int32 id = 1;
int32 topLayer = 2;
int32 baseLayer = 3;
}
enum MultipleFracAction
{
NONE = 0;
APPEND_FRACTURES = 1;
REPLACE_FRACTURES = 2;
}
message CreateMultipleFracRequest
{
int32 caseId = 1;
int32 templateId = 2;
repeated string wellPathNames = 3;
double minDistFromWellTd = 4;
int32 maxFracturesPerWell = 5;
int32 topLayer = 6;
int32 baseLayer = 7;
int32 spacing = 8;
MultipleFracAction action = 9;
}
enum LgrSplitType
{
LGR_PER_CELL = 0;
LGR_PER_COMPLETION = 1;
LGR_PER_WELL = 2;
}
message CreateLgrForCompRequest
{
int32 caseId = 1;
int32 timeStep = 2;
repeated string wellPathNames = 3;
int32 refinementI = 4;
int32 refinementJ = 5;
int32 refinementK = 6;
LgrSplitType splitType = 7;
}
message CreateSatPressPlotRequest
{
repeated int32 caseIds = 1;
}
message CreateGridCaseGroupRequest
{
repeated string casePaths = 1;
}
message CreateStatisticsCaseRequest
{
int32 caseGroupId = 1;
}
message ExportFlowInfoRequest
{
int32 caseId = 1;
repeated int32 timeSteps = 2;
repeated string injectors = 3;
repeated string producers = 4;
string fileName = 5;
double minimumCommunication = 6;
double aquiferCellThreshold = 7;
}
message CreateViewRequest
{
int32 caseId = 1;
}
message CloneViewRequest
{
int32 viewId = 1;
}
message CreateWbsPlotRequest
{
int32 caseId = 1;
string wellPath = 2;
int32 timeStep = 3;
PdmObject wbsParameters = 4;
}
message ImportWellPathsRequest
{
string wellPathFolder = 1;
repeated string wellPathFiles = 2;
}
message ImportWellLogFilesRequest
{
string wellLogFolder = 1;
repeated string wellLogFiles = 2;
}
message ImportFormationNamesRequest
{
repeated string formationFiles = 1;
int32 applyToCaseId = 2;
}
enum ExportFormat
{
LAS = 0;
ASCII = 1;
}
message ExportWellLogPlotDataRequest
{
ExportFormat exportFormat = 1;
int32 viewId = 2;
string exportFolder = 3;
string filePrefix = 4;
bool exportTvdRkb = 5;
bool capitalizeFileNames = 6;
double resampleInterval = 7;
bool convertCurveUnits = 8;
}
message ExportContourMapToTextRequest
{
string exportFileName = 1;
bool exportLocalCoordinates = 2;
string undefinedValueLabel = 3;
bool excludeUndefinedValues = 4;
int32 viewId = 5;
}
message SaveProjectRequest
{
string filePath = 1;
}
/* CommandParams handles both command name and parameters in one.
* The message type and content is used as parameters and
* the name of the variable is used to find the command name. */
message CommandParams
{
/* Since only one of these oneof-parameters can be set, we know which
* command to run from the name of parameter. I.e. if openProject is set
* we will run the RicfOpenProject command with the parameters set in
* the FilePathRequest message. */
oneof params
{
FilePathRequest openProject = 1;
Empty closeProject = 2;
FilePathRequest setStartDir = 3;
FilePathRequest loadCase = 4;
ReplaceCaseRequest replaceCase = 5;
ReplaceSourceCasesRequest replaceSourceCases = 6;
ExportMultiCaseRequest exportMultiCaseSnapshots = 7;
ExportSnapshotsRequest exportSnapshots = 8;
ExportPropertyRequest exportProperty = 9;
ExportPropertyInViewsRequest exportPropertyInViews = 10;
ExportWellPathCompRequest exportWellPathCompletions = 11;
ExportSimWellPathFracRequest exportSimWellFractureCompletions = 12;
ExportMswRequest exportMsw = 13;
ExportWellPathRequest exportWellPaths = 14;
ExportVisibleCellsRequest exportVisibleCells = 15;
SetExportFolderRequest setExportFolder = 16;
RunOctaveScriptRequest runOctaveScript = 17;
SetWindowSizeParams setMainWindowSize = 18;
ComputeCaseGroupStatRequest computeCaseGroupStatistics = 19;
SetTimeStepParams setTimeStep = 20;
ScaleFractureTemplateRequest scaleFractureTemplate = 21;
SetFracContainmentRequest setFractureContainment = 22;
CreateMultipleFracRequest createMultipleFractures = 23;
CreateLgrForCompRequest createLgrForCompletions = 24;
CreateSatPressPlotRequest createSaturationPressurePlots = 25;
ReplaceCaseRequests replaceMultipleCases = 26;
CreateGridCaseGroupRequest createGridCaseGroup = 27;
CreateStatisticsCaseRequest createStatisticsCase = 28;
ExportFlowInfoRequest exportFlowCharacteristics = 29;
CreateViewRequest createView = 30;
CloneViewRequest cloneView = 31;
CreateWbsPlotRequest createWellBoreStabilityPlot = 32;
ImportWellPathsRequest importWellPaths = 33;
ImportWellLogFilesRequest importWellLogFiles = 34;
ImportFormationNamesRequest importFormationNames = 35;
ExportWellLogPlotDataRequest exportWellLogPlotData = 36;
SetWindowSizeParams setPlotWindowSize = 37;
ExportContourMapToTextRequest exportContourMapToText = 38;
SaveProjectRequest saveProject = 39;
}
}
message GridCaseGroupResult
{
int32 groupId = 1;
string groupName = 2;
}
message CreateStatisticsCaseResult
{
int32 caseId = 1;
}
message CreateViewResult
{
int32 viewId = 1;
}
message CreateWbsPlotResult
{
int32 viewId = 1;
}
message ImportWellPathsResult
{
repeated string wellPathNames = 1;
}
message ImportWellLogFilesResult
{
repeated string wellPathNames = 1;
}
message ExportWellLogPlotDataResult
{
repeated string exportedFiles = 1;
}
/* Command reply handles the return values for the generic command
* The name of the variable is used to map to the cafPdmObject classKeyword */
message CommandReply
{
oneof result
{
Empty emptyResult = 1;
CaseRequest loadCaseResult = 2;
GridCaseGroupResult createGridCaseGroupResult = 3;
CreateStatisticsCaseResult createStatisticsCaseResult = 4;
CreateViewResult createViewResult = 5;
CreateWbsPlotResult createWbsPlotResult = 6;
ImportWellPathsResult importWellPathsResult = 7;
ImportWellLogFilesResult importWellLogFilesResult = 8;
ExportWellLogPlotDataResult exportWellLogPlotDataResult = 9;
}
}

View File

@@ -0,0 +1,46 @@
syntax = "proto3";
package rips;
message Empty
{
}
message ClientToServerStreamReply
{
int64 accepted_value_count = 1;
}
message Vec3i {
int32 i = 1;
int32 j = 2;
int32 k = 3;
}
message Vec3d
{
double x = 1;
double y = 2;
double z = 3;
}
message CellCenters
{
repeated Vec3d centers = 1;
}
message CellCorners {
Vec3d c0 = 1;
Vec3d c1 = 2;
Vec3d c2 = 3;
Vec3d c3 = 4;
Vec3d c4 = 5;
Vec3d c5 = 6;
Vec3d c6 = 7;
Vec3d c7 = 8;
}
message CellCornersArray
{
repeated CellCorners cells = 1;
}

View File

@@ -0,0 +1,25 @@
syntax = "proto3";
package rips;
import "Definitions.proto";
import "Case.proto";
service Grid
{
rpc GetCellCenters(GridRequest) returns(stream CellCenters) {}
rpc GetCellCorners(GridRequest) returns(stream CellCornersArray) {}
rpc GetDimensions(GridRequest) returns (GridDimensions) {}
}
message GridRequest
{
CaseRequest case_request = 1;
int32 grid_index = 2;
}
message GridDimensions
{
Vec3i dimensions = 1;
}

View File

@@ -0,0 +1,76 @@
syntax = "proto3";
import "Case.proto";
import "Definitions.proto";
package rips;
service NNCProperties
{
rpc GetAvailableNNCProperties(CaseRequest) returns (AvailableNNCProperties) {}
rpc GetNNCConnections(CaseRequest) returns (stream NNCConnections) {}
rpc GetNNCValues(NNCValuesRequest) returns (stream NNCValues) {}
rpc SetNNCValues(stream NNCValuesChunk) returns (ClientToServerStreamReply) {}
}
enum NNCPropertyType
{
NNC_DYNAMIC = 0;
NNC_STATIC = 1;
NNC_GENERATED = 2;
}
message AvailableNNCProperty
{
string name = 1;
NNCPropertyType property_type = 2;
}
message AvailableNNCProperties
{
repeated AvailableNNCProperty properties = 1;
}
message NNCConnection
{
int32 cell_grid_index1 = 1;
int32 cell_grid_index2 = 2;
Vec3i cell1 = 3;
Vec3i cell2 = 4;
}
message NNCConnections
{
repeated NNCConnection connections = 1;
}
message NNCValuesRequest
{
int32 case_id = 1;
string property_name = 2;
NNCPropertyType property_type = 3;
int32 time_step = 4;
}
message NNCValues
{
repeated double values = 1;
}
message NNCValuesInputRequest
{
int32 case_id = 1;
string property_name = 2;
PorosityModelType porosity_model = 3;
int32 time_step = 4;
}
message NNCValuesChunk
{
oneof ChunkType
{
// Params needs to be sent in the first message
NNCValuesInputRequest params = 1;
NNCValues values = 2;
}
}

View File

@@ -0,0 +1,111 @@
syntax = "proto3";
import "Definitions.proto";
package rips;
service PdmObjectService
{
rpc GetDescendantPdmObjects(PdmDescendantObjectRequest) returns (PdmObjectArray) {}
rpc GetChildPdmObjects(PdmChildObjectRequest) returns (PdmObjectArray) {}
rpc GetAncestorPdmObject(PdmParentObjectRequest) returns (PdmObject) {}
rpc CreateChildPdmObject(CreatePdmChildObjectRequest) returns (PdmObject) {}
rpc UpdateExistingPdmObject(PdmObject) returns (Empty) {}
rpc CallPdmObjectGetter(PdmObjectGetterRequest) returns (stream PdmObjectGetterReply) {}
rpc CallPdmObjectSetter(stream PdmObjectSetterChunk) returns (ClientToServerStreamReply) {}
rpc CallPdmObjectMethod(PdmObjectMethodRequest) returns (PdmObject) {}
}
message PdmDescendantObjectRequest
{
PdmObject object = 1;
string child_keyword = 2;
}
message PdmChildObjectRequest
{
PdmObject object = 1;
string child_field = 2;
}
message CreatePdmChildObjectRequest
{
PdmObject object = 1;
string child_field = 2;
}
message PdmParentObjectRequest
{
PdmObject object = 1;
string parent_keyword = 2;
}
message PdmObject
{
string class_keyword = 1;
uint64 address = 2;
map<string, string> parameters = 3;
bool visible = 4;
bool persistent = 5; // Does this object live on in ResInsight?
}
message PdmObjectArray
{
repeated PdmObject objects = 1;
}
message PdmObjectGetterRequest
{
PdmObject object = 1;
string method = 2;
}
message PdmObjectSetterRequest
{
PdmObjectGetterRequest request = 1;
int32 data_count = 2;
}
message PdmObjectSetterChunk
{
oneof data
{
PdmObjectSetterRequest set_request = 1;
DoubleArray doubles = 2;
IntArray ints = 3;
StringArray strings = 4;
}
}
message DoubleArray
{
repeated double data = 1;
}
message IntArray
{
repeated int32 data = 1;
}
message StringArray
{
repeated string data = 1;
}
message PdmObjectGetterReply
{
oneof data
{
DoubleArray doubles = 1;
IntArray ints = 2;
StringArray strings = 3;
}
}
message PdmObjectMethodRequest
{
PdmObject object = 1;
string method = 2;
PdmObject params = 3;
}

View File

@@ -0,0 +1,16 @@
syntax = "proto3";
import "Definitions.proto";
import "Case.proto";
import "PdmObject.proto";
package rips;
service Project {
rpc GetCurrentCase(Empty) returns (CaseRequest) {}
rpc GetSelectedCases(Empty) returns (CaseInfoArray) {}
rpc GetAllCaseGroups(Empty) returns (CaseGroups) {}
rpc GetAllCases(Empty) returns (CaseInfoArray) {}
rpc GetCasesInGroup(CaseGroup) returns (CaseInfoArray) {}
rpc GetPdmObject(Empty) returns (PdmObject) {}
}

View File

@@ -0,0 +1,72 @@
syntax = "proto3";
import "Definitions.proto";
import "Case.proto";
package rips;
service Properties
{
rpc GetAvailableProperties(AvailablePropertiesRequest) returns (AvailableProperties) {}
rpc GetActiveCellProperty(PropertyRequest) returns (stream PropertyChunk) {}
rpc GetSelectedCellProperty(PropertyRequest) returns (stream PropertyChunk) {}
rpc GetGridProperty(PropertyRequest) returns (stream PropertyChunk) {}
rpc SetActiveCellProperty(stream PropertyInputChunk) returns (ClientToServerStreamReply) {}
rpc SetGridProperty(stream PropertyInputChunk) returns (ClientToServerStreamReply) {}
}
enum PropertyType
{
DYNAMIC_NATIVE = 0;
STATIC_NATIVE = 1;
SOURSIMRL = 2;
GENERATED = 3;
INPUT_PROPERTY = 4;
FORMATION_NAMES = 5;
FLOW_DIAGNOSTICS = 6;
INJECTION_FLOODING = 7;
REMOVED = 8;
UNDEFINED = 999;
}
message AvailablePropertiesRequest
{
CaseRequest case_request = 1;
PropertyType property_type = 2;
PorosityModelType porosity_model = 3;
}
message AvailableProperties
{
repeated string property_names = 1;
}
message PropertyRequest
{
CaseRequest case_request = 1;
PropertyType property_type = 2;
string property_name = 3;
int32 time_step = 4;
int32 grid_index = 5;
PorosityModelType porosity_model = 6;
}
message TimeStep
{
int32 index = 1;
}
message PropertyInputChunk
{
oneof ChunkType
{
// Params needs to be sent in the first message
PropertyRequest params = 1;
PropertyChunk values = 2;
}
}
message PropertyChunk
{
repeated double values = 1;
}

View File

@@ -0,0 +1,37 @@
syntax = "proto3";
import "Definitions.proto";
package rips;
service SimulationWell
{
rpc GetSimulationWellStatus(SimulationWellRequest) returns (SimulationWellStatus) {}
rpc GetSimulationWellCells(SimulationWellRequest) returns (SimulationWellCellInfoArray) {}
}
message SimulationWellRequest {
int32 case_id = 1;
string well_name = 2;
int32 timestep = 3;
}
message SimulationWellStatus
{
string well_type = 1;
bool is_open = 2;
}
message SimulationWellCellInfo {
Vec3i ijk = 1;
int32 grid_index = 2;
bool is_open = 3;
int32 branch_id = 4;
int32 segment_id = 5;
}
message SimulationWellCellInfoArray
{
repeated SimulationWellCellInfo data = 1;
}

18
GrpcInterface/Python/.gitignore vendored Normal file
View File

@@ -0,0 +1,18 @@
__pycache__
.pytest_cache
generated
dist
build
rips.egg-info
setup.py
grpc
grpcio*
six*
easy_install*
bin*
grpc_tools
pkg_resources
google
protobuf*
setuptools*
extern*

View File

@@ -0,0 +1,14 @@
Copyright (C) 2019- Equinor ASA
ResInsight is free software: you can redistribute it andor modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License at <http:www.gnu.orglicensesgpl.html>
for more details.

View File

@@ -0,0 +1,4 @@
include *.txt
include *.md
include LICENSE
recursive-include rips *.py

View File

@@ -0,0 +1,5 @@
# ResInsight Processing Server - rips
A Python interface for the ResInsight visualization and post-processing suite for Reservoir Simulations
[Learn More](https://www.resinsight.org)

View File

@@ -0,0 +1,6 @@
Set working folder to /rips
---------------------------
python -m autopep8 --in-place --recursive .
Adjustments to behaviour is configured in setup.cfg at repository top level, in section [pep8]

View File

@@ -0,0 +1,26 @@
######################################################################
# All this is based on the MANIFEST.in and setup.py in Python-folder
######################################################################
# 1. Make sure dist folder is clear
del dist/*
# 2. Update rips-version tag in setup.py (".N after ResInsight version"). This is generated from setup.py.cmake
# So that you for instance have version 2019.08.1 of rips.
# 3. Build source distribution
python setup.py sdist
# 4. Test upload to test.pypi.org. This requires a ResInsight testpypi-user and you will be prompted for username and password
python -m twine upload --repository-url https://test.pypi.org/legacy/ dist/*
# 5. Test install rips module.
pip install --index-url https://test.pypi.org/simple/ rips
# 6. Test the newly installed module
# 8. If anything is wrong, start again from 1. with an incremented rips-version (ResInsightVersion.2+)
# These incremented versions are just for testpypi and you can reset back to the wanted version before real upload
# 9. Upload to real Pypi. This requires a ResInsight pypi-user.
python -m twine upload dist/*

View File

@@ -0,0 +1,7 @@
You need sphinx to update the documentation.
pip install sphinx sphinx-markdown-builder
To update run "make markdown" to update to reflect changes to the python code.
The generated files are located in build/markdown

View File

@@ -0,0 +1,35 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=source
set BUILDDIR=build
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd

View File

@@ -0,0 +1,39 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=source
set BUILDDIR=build
if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd
REM Copy files to deployment folder using second parameter
REM Example "d:\gitroot\ResInsight-UserDocumentation\content\scripting"
xcopy /Y build\markdown %2

View File

@@ -0,0 +1,134 @@
+++
title = "Python Examples"
published = true
weight = 40
+++
![]({{< relref "" >}}images/scripting/python-logo-master-v3-TM.png)
This pages is created based on the content in the **PythonExamples** folder located inside the **rips** module, made available online for convenience.
AllCases
--------
.. literalinclude:: ../../rips/PythonExamples/all_cases.py
AllSimulationWells
------------------
.. literalinclude:: ../../rips/PythonExamples/all_simulation_wells.py
AllWells
--------
.. literalinclude:: ../../rips/PythonExamples/all_wells.py
AlterWbsPlot
------------
.. literalinclude:: ../../rips/PythonExamples/alter_wbs_plot.py
CaseGridGroup
-------------
.. literalinclude:: ../../rips/PythonExamples/case_grid_group.py
CaseInfoStreamingExample
------------------------
.. literalinclude:: ../../rips/PythonExamples/case_info_streaming_example.py
CellResultData
--------------
.. literalinclude:: ../../rips/PythonExamples/cell_result_data.py
CommandExample
--------------
.. literalinclude:: ../../rips/PythonExamples/command_example.py
Create WBS Plot
---------------
.. literalinclude:: ../../rips/PythonExamples/create_wbs_plot.py
ErrorHandling
-------------
.. literalinclude:: ../../rips/PythonExamples/error_handling.py
ExportContourMaps
-----------------
.. literalinclude:: ../../rips/PythonExamples/export_contour_maps.py
ExportPlots
-----------
.. literalinclude:: ../../rips/PythonExamples/export_plots.py
ExportSnapshots
---------------
.. literalinclude:: ../../rips/PythonExamples/export_snapshots.py
GridInformation
---------------
.. literalinclude:: ../../rips/PythonExamples/grid_information.py
Import Well Paths
-----------------
.. literalinclude:: ../../rips/PythonExamples/import_well_paths_and_logs.py
InputPropTestAsync
------------------
.. literalinclude:: ../../rips/PythonExamples/input_prop_test_async.py
InputPropTestSync
-----------------
.. literalinclude:: ../../rips/PythonExamples/input_prop_test_sync.py
InstanceExample
---------------
.. literalinclude:: ../../rips/PythonExamples/instance_example.py
LaunchWithCommandLineOptions
----------------------------
.. literalinclude:: ../../rips/PythonExamples/launch_with_commandline_options.py
Launch Using Command Line Options
---------------------------------
.. literalinclude:: ../../rips/PythonExamples/launch_with_commandline_options.py
NewSummaryPlot
--------------
.. literalinclude:: ../../rips/PythonExamples/new_summary_plot.py
SelectedCases
-------------
.. literalinclude:: ../../rips/PythonExamples/selected_cases.py
SelectedCells
-------------
.. literalinclude:: ../../rips/PythonExamples/selected_cells.py
SetCellResult
-------------
.. literalinclude:: ../../rips/PythonExamples/set_cell_result.py
SetFlowDiagnosticsResult
------------------------
.. literalinclude:: ../../rips/PythonExamples/set_flow_diagnostics_result.py
SetGridProperties
-----------------
.. literalinclude:: ../../rips/PythonExamples/set_grid_properties.py
SoilAverageAsync
----------------
.. literalinclude:: ../../rips/PythonExamples/soil_average_async.py
SoilAverageSync
---------------
.. literalinclude:: ../../rips/PythonExamples/soil_average_sync.py
SoilPorvAsync
-------------
.. literalinclude:: ../../rips/PythonExamples/soil_porv_async.py
SoilPorvSync
------------
.. literalinclude:: ../../rips/PythonExamples/soil_porv_sync.py
ViewExample
-----------
.. literalinclude:: ../../rips/PythonExamples/view_example.py

View File

@@ -0,0 +1,9 @@
+++
title = "Python API - rips"
published = true
weight = 42
+++
![]({{< relref "" >}}images/scripting/python-logo-master-v3-TM.png)
.. include:: rips.rst

View File

@@ -0,0 +1,67 @@
# Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# http://www.sphinx-doc.org/en/master/config
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys
sys.path.insert(0, os.path.abspath('../../'))
# -- Project information -----------------------------------------------------
project = 'rips'
copyright = '2019, Ceetron Solutions AS'
author = 'Ceetron Solutions AS'
# The full version, including alpha/beta/rc tags
release = '2019.04.01'
# -- General configuration ---------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.napoleon',
'sphinx_markdown_builder'
]
master_doc = 'PythonRips'
napoleon_google_docstring = True
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['build/*', 'rips.rst']
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'alabaster'
smartquotes = False
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# -- Extension configuration -------------------------------------------------

View File

@@ -0,0 +1,113 @@
Instance Module
===============
.. autoclass:: rips.instance.Instance
:members:
Example
-------
.. literalinclude:: ../../rips/PythonExamples/instance_example.py
:language: python
:lines: 5-
:emphasize-lines: 3
Case Module
===========
.. autoclass:: rips.case.Case
:members:
Example
-------
.. literalinclude:: ../../rips/PythonExamples/all_cases.py
:language: python
:lines: 5-
:emphasize-lines: 5
Contour Map Module
==================
.. autoclass:: rips.contour_map.EclipseContourMap
:members:
.. autoclass:: rips.contour_map.GeoMechContourMap
:members:
Grid Module
===========
.. autoclass:: rips.grid.Grid
:members:
Example
-------
.. code-block:: python
case = rips_instance.project.loadCase(path=casePath)
print (case.gridCount())
if case.gridCount() > 0:
grid = case.grid(index=0)
dimensions = grid.dimensions()
print(dimensions.i)
print(dimensions.j)
print(dimensions.k)
GridCaseGroup Module
====================
.. autoclass:: rips.gridcasegroup.GridCaseGroup
:members:
Plot Module
==============
.. autoclass:: rips.project.Plot
:members:
Project Module
==============
.. autoclass:: rips.project.Project
:members:
Simulation Well Module
======================
.. autoclass:: rips.simulation_well.SimulationWell
:members:
View Module
===========
.. autoclass:: rips.view.View
:members:
Well Log Plot Module
====================
.. autoclass:: rips.well_log_plot.WellLogPlot
:members:
Synchronous Example
-------------------
Read two properties, multiply them together and push the results back to ResInsight in a naïve way, by reading PORO into a list, then reading PERMX into a list, then multiplying them both in a resulting list and finally transferring back the list.
This is slow and inefficient, but works.
.. literalinclude:: ../../rips/PythonExamples/input_prop_test_async.py
:language: python
:lines: 5-
Asynchronous Example
--------------------
Read two properties at the same time chunk by chunk, multiply each chunk together and start transferring the result back to ResInsight as soon as the chunk is finished.
This is far more efficient.
.. literalinclude:: ../../rips/PythonExamples/input_prop_test_sync.py
:language: python
:lines: 5-

View File

@@ -0,0 +1,3 @@
grpcio
grpcio-tools
protobuf

View File

@@ -0,0 +1,36 @@
###################################################################################
# This example will connect to ResInsight, retrieve a list of cases and print info
#
###################################################################################
# Import the ResInsight Processing Server Module
import rips
# Connect to ResInsight
resinsight = rips.Instance.find()
if resinsight is not None:
# Get a list of all cases
cases = resinsight.project.cases()
print ("Got " + str(len(cases)) + " cases: ")
for case in cases:
print("Case id: " + str(case.id))
print("Case name: " + case.name)
print("Case type: " + case.__class__.__name__)
print("Case file name: " + case.file_path)
print("Case reservoir bounding box:", case.reservoir_boundingbox())
timesteps = case.time_steps()
for t in timesteps:
print("Year: " + str(t.year))
print("Month: " + str(t.month))
if isinstance(case, rips.EclipseCase):
print ("Getting coarsening info for case: ", case.name, case.id)
coarsening_info = case.coarsening_info()
if coarsening_info:
print("Coarsening information:")
for c in coarsening_info:
print("[{}, {}, {}] - [{}, {}, {}]".format(c.min.x, c.min.y, c.min.z,
c.max.x, c.max.y, c.max.z))

View File

@@ -0,0 +1,27 @@
###################################################################################
# This example will connect to ResInsight, retrieve a list of
# simulation wells and print info
###################################################################################
# Import the ResInsight Processing Server Module
import rips
# Connect to ResInsight
resinsight = rips.Instance.find()
if resinsight is not None:
# Get a list of all wells
cases = resinsight.project.cases()
for case in cases:
print("Case id: " + str(case.id))
print("Case name: " + case.name)
timesteps = case.time_steps()
sim_wells = case.simulation_wells()
for sim_well in sim_wells:
print("Simulation well: " + sim_well.name)
for (tidx, timestep) in enumerate(timesteps):
status = sim_well.status(tidx)
cells = sim_well.cells(tidx)
print("timestep: " + str(tidx) + " type: " + status.well_type + " open: " + str(status.is_open) + " cells:" + str(len(cells)))

View File

@@ -0,0 +1,17 @@
###################################################################################
# This example will connect to ResInsight, retrieve a list of wells and print info
#
###################################################################################
# Import the ResInsight Processing Server Module
import rips
# Connect to ResInsight
resinsight = rips.Instance.find()
if resinsight is not None:
# Get a list of all wells
wells = resinsight.project.well_paths()
print ("Got " + str(len(wells)) + " wells: ")
for well in wells:
print("Well name: " + well.name)

View File

@@ -0,0 +1,29 @@
# Load ResInsight Processing Server Client Library
import rips
import tempfile
# Connect to ResInsight instance
resinsight = rips.Instance.find()
# Get the project
project = resinsight.project
# Find all the well bore stability plots in the project
wbsplots = project.descendants(rips.WellBoreStabilityPlot)
# Chose a sensible output folder
dirname = tempfile.gettempdir()
# Loop through all Well Bore Stability plots
for wbsplot in wbsplots:
# Set depth type a parameter and export snapshot
wbsplot.depth_type = "TRUE_VERTICAL_DEPTH_RKB"
# Example of setting parameters for existing plots
params = wbsplot.parameters()
params.user_poisson_ratio = 0.12345
params.update()
wbsplot.update()
wbsplot.export_snapshot(export_folder=dirname)

View File

@@ -0,0 +1,27 @@
import os
import rips
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 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)
case_group.print_object_info()
#stat_cases = caseGroup.statistics_cases()
#case_ids = []
#for stat_case in stat_cases:
# stat_case.set_dynamic_properties_to_calculate(["SWAT"])
# case_ids.append(stat_case.id)
case_group.compute_statistics()
view = case_group.views()[0]
cell_result = view.cell_result()
cell_result.set_result_variable("PRESSURE_DEV")

View File

@@ -0,0 +1,27 @@
###############################################################################
# This example will get the cell info for the active cells for the first case
###############################################################################
# Import the ResInsight Processing Server Module
import rips
# Connect to ResInsight
resinsight = rips.Instance.find()
# Get the first case. This will fail if you haven't loaded any cases
case = resinsight.project.cases()[0]
# Get the cell count object
cell_counts = case.cell_count()
print("Number of active cells: " + str(cell_counts.active_cell_count))
print("Total number of reservoir cells: " + str(cell_counts.reservoir_cell_count))
# Get information for all active cells
active_cell_infos = case.cell_info_for_active_cells()
# A simple check on the size of the cell info
assert(cell_counts.active_cell_count == len(active_cell_infos))
# Print information for the first active cell
print("First active cell: ")
print(active_cell_infos[0])

View File

@@ -0,0 +1,17 @@
######################################################################
# This script retrieves cell result data and alters it
######################################################################
import rips
resinsight = rips.Instance.find()
view = resinsight.project.views()[0]
results = view.cell_result_data()
print ("Number of result values: ", len(results))
newresults = []
for i in range(0, len(results)):
newresults.append(results[i] * -1.0)
view.set_cell_result_data(newresults)

View File

@@ -0,0 +1,57 @@
###############################################################################
# This example will show setting time step, window size and export snapshots and properties
###############################################################################
import os
import tempfile
import rips
# Load instance
resinsight = rips.Instance.find()
# Set window sizes
resinsight.set_main_window_size(width=800, height=500)
resinsight.set_plot_window_size(width=1000, height=1000)
# Retrieve first case
case = resinsight.project.cases()[0]
# Get a view
view1 = case.views()[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
with tempfile.TemporaryDirectory(prefix="rips") as tmpdirname:
print("Temporary folder: ", tmpdirname)
# Set export folder for snapshots and properties
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)
# Export properties in the view
view1.export_property()
# Check that the exported file exists
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))

View File

@@ -0,0 +1,109 @@
# Load ResInsight Processing Server Client Library
import rips
import tempfile
from os.path import expanduser
from pathlib import Path
# Connect to ResInsight instance
resinsight = rips.Instance.find()
# Example code
project = resinsight.project
# Look for input files in the home directory of the user
home_dir = expanduser("~")
elastic_properties_file_path = (Path(home_dir) / "elastic_properties.csv").as_posix()
print("Elastic properties file path:", elastic_properties_file_path)
facies_properties_file_path = (Path(home_dir) / "facies_id.roff").as_posix()
print("Facies properties file path:", facies_properties_file_path)
# Create stim plan model template
fmt_collection = project.descendants(rips.StimPlanModelTemplateCollection)[0]
stim_plan_model_template = fmt_collection.new_stim_plan_model_template(elastic_properties_file_path=elastic_properties_file_path,
facies_properties_file_path=facies_properties_file_path)
stim_plan_model_template.overburden_formation = "Garn"
stim_plan_model_template.overburden_facies = "Shale"
stim_plan_model_template.underburden_formation = "Garn"
stim_plan_model_template.underburden_facies = "Shale"
stim_plan_model_template.overburden_height = 68
stim_plan_model_template.update()
print("Overburden: ", stim_plan_model_template.overburden_formation)
# Set eclipse result for facies definition
eclipse_result = stim_plan_model_template.facies_properties().facies_definition()
eclipse_result.result_type = "INPUT_PROPERTY"
eclipse_result.result_variable = "OPERNUM_1"
eclipse_result.update()
# Set eclipse result for non-net layers
non_net_layers = stim_plan_model_template.non_net_layers()
non_net_layers_result = non_net_layers.facies_definition()
non_net_layers_result.result_type = "STATIC_NATIVE"
non_net_layers_result.result_variable = "NTG"
non_net_layers_result.update()
non_net_layers.formation = "Not"
non_net_layers.facies = "Shale"
non_net_layers.update()
# Add some scaling factors
elastic_properties = stim_plan_model_template.elastic_properties()
elastic_properties.add_property_scaling(formation="Garn", facies="Calcite", property="YOUNGS_MODULUS", scale=1.44)
well_name = "B-2 H"
# Find a well
well_path = project.well_path_by_name(well_name)
print("well path:", well_path)
stim_plan_model_collection = project.descendants(rips.StimPlanModelCollection)[0]
# Find a case
cases = resinsight.project.cases()
case = cases[0]
# Use the last time step
time_steps = case.time_steps()
time_step = time_steps[len(time_steps) - 1]
export_folder = tempfile.gettempdir()
stim_plan_models = []
# Create and export a StimPlan model for each depth
measured_depths = [ 3200.0, 3400.0, 3600.0 ]
for measured_depth in measured_depths:
# Create stim plan model at a give measured depth
stim_plan_model = stim_plan_model_collection.new_stim_plan_model(eclipse_case=case,
time_step=time_step,
well_path=well_path,
measured_depth=measured_depth,
stim_plan_model_template=stim_plan_model_template)
stim_plan_models.append(stim_plan_model)
# Make the well name safer to use as a directory path
well_name_part = well_name.replace(" ", "_")
directory_path = Path(export_folder) / '{}_{}'.format(well_name_part, int(measured_depth))
# Create the folder
directory_path.mkdir(parents=True, exist_ok=True)
print("Exporting fracture model to: ", directory_path)
stim_plan_model.export_to_file(directory_path=directory_path.as_posix())
# Create a fracture mode plot
stim_plan_model_plot_collection = project.descendants(rips.StimPlanModelPlotCollection)[0]
stim_plan_model_plot = stim_plan_model_plot_collection.new_stim_plan_model_plot(stim_plan_model=stim_plan_model)
print("Exporting fracture model plot to: ", directory_path)
stim_plan_model_plot.export_snapshot(export_folder=directory_path.as_posix())
print("Setting measured depth and perforation length.")
stim_plan_models[0].measured_depth = 3300.0
stim_plan_models[0].perforation_length = 123.445
stim_plan_models[0].update()

View File

@@ -0,0 +1,43 @@
import os
import grpc
# Load ResInsight Processing Server Client Library
import rips
# Connect to ResInsight instance
resInsight = rips.Instance.find()
# Get all GeoMech cases
cases = resInsight.project.descendants(rips.GeoMechCase)
# Get all well paths
well_paths = resInsight.project.well_paths()
# Ensure there's at least one well path
if len(well_paths) < 1:
print("No well paths in project")
exit(1)
# Create a set of WbsParameters
params = rips.WbsParameters()
params.user_poisson_ratio = 0.23456
params.user_ucs = 123
# Loop through all cases
for case in cases:
assert(isinstance(case, rips.GeoMechCase))
min_res_depth, max_res_depth = case.reservoir_depth_range()
# Find a good output path
case_path = case.file_path
folder_name = os.path.dirname(case_path)
# Import formation names
case.import_formation_names(formation_files=['D:/Projects/ResInsight-regression-test/ModelData/norne/Norne_ATW2013.lyr'])
# create a folder to hold the snapshots
dirname = os.path.join(folder_name, 'snapshots')
print("Exporting to: " + dirname)
for well_path in well_paths[0:4]: # Loop through the first five well paths
# Create plot with parameters
wbsplot = case.create_well_bore_stability_plot(well_path=well_path.name, time_step=0, parameters=params)

View File

@@ -0,0 +1,76 @@
###################################################################
# This example demonstrates the use of ResInsight exceptions
# for proper error handling
###################################################################
import rips
import grpc
import tempfile
resinsight = rips.Instance.find()
case = None
# Try loading a non-existing case. We should get a grpc.RpcError exception from the server
try:
case = resinsight.project.load_case("Nonsense")
except grpc.RpcError as e:
print("Expected Server Exception Received while loading case: ", e.code(), e.details())
# Try loading well paths from a non-existing folder. We should get a grpc.RpcError exception from the server
try:
well_path_files = resinsight.project.import_well_paths(well_path_folder="NONSENSE/NONSENSE")
except grpc.RpcError as e:
print("Expected Server Exception Received while loading wellpaths: ", e.code(), e.details())
# Try loading well paths from an existing but empty folder. We should get a warning.
try:
with tempfile.TemporaryDirectory() as tmpdirname:
well_path_files = resinsight.project.import_well_paths(well_path_folder=tmpdirname)
assert(len(well_path_files) == 0)
assert(resinsight.project.has_warnings())
print("Should get warnings below")
for warning in resinsight.project.warnings():
print (warning)
except grpc.RpcError as e:
print("Unexpected Server Exception caught!!!", e)
case = resinsight.project.case(case_id=0)
if case is not None:
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.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!")
# Add another value, so this is outside the bounds of the active cell result storage
results.append(1.0)
# This time we should get a grpc.RpcError exception, which is a server side error.
try:
case.set_active_cell_property(results, 'GENERATED', 'POROAPPENDED', 0)
print("Everything went well??")
except grpc.RpcError as e:
print("Expected Server Exception Received: ", e)
except IndexError:
print ("Got index out of bounds error. This shouldn't happen here")
# 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.chunk_size = active_cell_count
try:
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")
except IndexError:
print ("Got expected index out of bounds error on client side")

View File

@@ -0,0 +1,32 @@
# Load ResInsight Processing Server Client Library
import rips
import tempfile
import pathlib
# Connect to ResInsight instance
resInsight = rips.Instance.find()
# Data will be written to temp
tmpdir = pathlib.Path(tempfile.gettempdir())
# Find all eclipse contour maps of the project
contour_maps = resInsight.project.descendants(rips.EclipseContourMap)
print("Number of eclipse contour maps:", len(contour_maps))
# Export the contour maps to a text file
for (index, contour_map) in enumerate(contour_maps):
filename = "eclipse_contour_map" + str(index) + ".txt"
filepath = tmpdir / filename
print("Exporting to:", filepath)
contour_map.export_to_text(str(filepath))
# The contour maps is also available for a Case
cases = resInsight.project.cases()
for case in cases:
contour_maps = case.descendants(rips.GeoMechContourMap)
# Export the contour maps to a text file
for (index, contour_map) in enumerate(contour_maps):
filename = "geomech_contour_map" + str(index) + ".txt"
filepath = tmpdir / filename
print("Exporting to:", filepath)
contour_map.export_to_text(str(filepath))

View File

@@ -0,0 +1,20 @@
# Import the tempfile module
import tempfile
# Load ResInsight Processing Server Client Library
import rips
# Connect to ResInsight instance
resInsight = rips.Instance.find()
# Get a list of all plots
plots = resInsight.project.plots()
export_folder = tempfile.mkdtemp()
print("Exporting to: " + export_folder)
for plot in plots:
plot.export_snapshot(export_folder=export_folder)
plot.export_snapshot(export_folder=export_folder, output_format='PDF')
if isinstance(plot, rips.WellLogPlot):
plot.export_data_as_las(export_folder=export_folder)
plot.export_data_as_ascii(export_folder=export_folder)

View File

@@ -0,0 +1,44 @@
############################################################################
# This script will export snapshots for two properties in every loaded case
# And put them in a snapshots folder in the same folder as the case grid
############################################################################
import os
import rips
# Load instance
resinsight = rips.Instance.find()
cases = resinsight.project.cases()
# Set main window size
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.id)
# Get grid path and its folder name
case_path = case.file_path
folder_name = os.path.dirname(case_path)
# create a folder to hold the snapshots
dirname = os.path.join(folder_name, 'snapshots')
if os.path.exists(dirname) is False:
os.mkdir(dirname)
print ("Exporting to folder: " + dirname)
resinsight.set_export_folder(export_type='SNAPSHOTS', path=dirname)
time_steps = case.time_steps()
print('Number of time_steps: ' + str(len(time_steps)))
for view in case.views():
if view.is_eclipse_view():
for property in property_list:
view.apply_cell_result(result_type='DYNAMIC_NATIVE', result_variable=property)
for time_step in range(0, len(time_steps), 10):
view.set_time_step(time_step = time_step)
view.export_snapshot()

View File

@@ -0,0 +1,19 @@
######################################################################################
# This example prints information about the grids of all cases in the current project
######################################################################################
import rips
resinsight = rips.Instance.find()
cases = resinsight.project.cases()
print("Number of cases found: ", len(cases))
for case in cases:
print(case.name)
grids = case.grids()
print("Number of grids: ", len(grids))
for grid in grids:
print("Grid dimensions: ", grid.dimensions())

View File

@@ -0,0 +1,32 @@
# Load ResInsight Processing Server Client Library
import rips
# Connect to ResInsight instance
resInsight = rips.Instance.find()
well_paths = resInsight.project.import_well_paths(well_path_folder='D:/Projects/ResInsight-regression-test/ModelData/norne/wellpaths')
if resInsight.project.has_warnings():
for warning in resInsight.project.warnings():
print(warning)
for well_path in well_paths:
print("Imported from folder: " + well_path.name)
well_paths = resInsight.project.import_well_paths(well_path_files=['D:/Projects/ResInsight-regression-test/ModelData/Norne_WellPaths/E-3H.json',
'D:/Projects/ResInsight-regression-test/ModelData/Norne_WellPaths/C-1H.json'])
if resInsight.project.has_warnings():
for warning in resInsight.project.warnings():
print(warning)
for well_path in well_paths:
print("Imported from individual files: " + well_path.name)
well_path_names = resInsight.project.import_well_log_files(well_log_folder='D:/Projects/ResInsight-regression-test/ModelData/Norne_PLT_LAS')
if resInsight.project.has_warnings():
for warning in resInsight.project.warnings():
print(warning)
for well_path_name in well_path_names:
print("Imported well log file for: " + well_path_name)

View File

@@ -0,0 +1,38 @@
########################################################################################
# This example generates a derived property in an asynchronous manner
# Meaning it does not wait for all the data for each stage to be read before proceeding
########################################################################################
import rips
import time
# Internal function for creating a result from a small chunk of poro and permx results
# The return value of the function is a generator for the results rather than the result itself.
def create_result(poro_chunks, permx_chunks):
# Loop through all the chunks of poro and permx in order
for (poroChunk, permxChunk) in zip(poro_chunks, permx_chunks):
resultChunk = []
# Loop through all the values inside the chunks, in order
for (poro, permx) in zip(poroChunk.values, permxChunk.values):
resultChunk.append(poro * permx)
# Return a generator object that behaves like a Python iterator
yield resultChunk
resinsight = rips.Instance.find()
start = time.time()
case = resinsight.project.cases()[0]
# Get a generator for the poro results. The generator will provide a chunk each time it is iterated
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.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.set_active_cell_property_async(create_result(poro_chunks, permx_chunks),
'GENERATED', 'POROPERMXAS', 0)
end = time.time()
print("Time elapsed: ", end - start)
print("Transferred all results back")
view = case.views()[0].apply_cell_result('GENERATED', 'POROPERMXAS')

View File

@@ -0,0 +1,35 @@
########################################################################################
# This example generates a derived property in an synchronous manner
# Meaning it completes reading each result before calculating the derived result
# See InputPropTestAsync for how to do this asynchronously instead.
########################################################################################
import rips
import time
import grpc
resinsight = rips.Instance.find()
start = time.time()
case = resinsight.project.cases()[0]
# Read poro result into list
poro_results = case.active_cell_property('STATIC_NATIVE', 'PORO', 0)
# Read permx result into list
permx_results = case.active_cell_property('STATIC_NATIVE', 'PERMX', 0)
# Generate output result
results = []
for (poro, permx) in zip(poro_results, permx_results):
results.append(poro * permx)
try:
# Send back output result
case.set_active_cell_property(results, 'GENERATED', 'POROPERMXSY', 0)
except grpc.RpcError as e:
print("Exception Received: ", e)
end = time.time()
print("Time elapsed: ", end - start)
print("Transferred all results back")
view = case.views()[0].apply_cell_result('GENERATED', 'POROPERMXSY')

View File

@@ -0,0 +1,11 @@
#######################################
# This example connects to ResInsight
#######################################
import rips
resinsight = rips.Instance.find()
if resinsight is None:
print('ERROR: could not find ResInsight')
else:
print('Successfully connected to ResInsight')

View File

@@ -0,0 +1,11 @@
# Load ResInsight Processing Server Client Library
import rips
# Launch ResInsight with last project file and a Window size of 600x1000 pixels
resinsight = rips.Instance.launch(command_line_parameters=['--last', '--size', 600, 1000])
# Get a list of all cases
cases = resinsight.project.cases()
print ("Got " + str(len(cases)) + " cases: ")
for case in cases:
print("Case name: " + case.name)
print("Case grid path: " + case.file_path)

View File

@@ -0,0 +1,16 @@
# Load ResInsight Processing Server Client Library
import rips
# Connect to ResInsight instance
resinsight = rips.Instance.find()
# Example code
print("ResInsight version: " + resinsight.version_string())
modeled_well_paths = resinsight.project.descendants(rips.ModeledWellPath)
for wellpath in modeled_well_paths:
geometry = wellpath.well_path_geometry()
geometry.print_object_info()
reference_point = geometry.reference_point
reference_point[0] += 100
geometry.update()
geometry.print_object_info()

View File

@@ -0,0 +1,11 @@
# Load ResInsight Processing Server Client Library
import rips
# Connect to ResInsight instance
resinsight = rips.Instance.find()
# Example code
project = resinsight.project
summary_cases = project.descendants(rips.SummaryCase)
summary_plot_collection = project.descendants(rips.SummaryPlotCollection)[0]
if len(summary_cases) > 0:
summary_plot = summary_plot_collection.new_summary_plot(summary_cases=summary_cases, address="FOP*")

View File

@@ -0,0 +1,9 @@
# Load ResInsight Processing Server Client Library
import rips
# Connect to ResInsight instance
resinsight = rips.Instance.find()
# Example code
print("ResInsight version: " + resinsight.version_string())
case = resinsight.project.case(case_id=0)
case.replace(new_grid_file='C:/Users/lindkvis/Projects/ResInsight/TestModels/Case_with_10_timesteps/Real0/BRUGGE_0000.EGRID')

View File

@@ -0,0 +1,20 @@
############################################################################
# This example returns the currently selected cases in ResInsight
# Because running this script in the GUI takes away the selection
# This script does not run successfully from within the ResInsight GUI
# And will need to be run from the command line separately from ResInsight
############################################################################
import rips
resinsight = rips.Instance.find()
if resinsight is not None:
cases = resinsight.project.selected_cases()
print ("Got " + str(len(cases)) + " cases: ")
for case in cases:
print(case.name)
for property in case.available_properties('DYNAMIC_NATIVE'):
print(property)

View File

@@ -0,0 +1,50 @@
############################################################################
# This example prints center and corners for the currently selected cells
# in ResInsight
############################################################################
import rips
resinsight = rips.Instance.find()
if resinsight is not None:
cases = resinsight.project.cases()
print ("Got " + str(len(cases)) + " cases: ")
for case in cases:
print(case.name)
cells = case.selected_cells()
print("Found " + str(len(cells)) + " selected cells")
time_step_info = case.time_steps()
for (idx, cell) in enumerate(cells):
print("Selected cell: [{}, {}, {}] grid: {}".format(cell.ijk.i+1, cell.ijk.j+1, cell.ijk.k+1, cell.grid_index))
# Get the grid and dimensions
grid = case.grids()[cell.grid_index]
dimensions = grid.dimensions()
# Map ijk to cell index
cell_index = dimensions.i * dimensions.j * cell.ijk.k + dimensions.i * cell.ijk.j + cell.ijk.i
# Print the cell center
cell_centers = grid.cell_centers()
cell_center = cell_centers[cell_index]
print("Cell center: [{}, {}, {}]".format(cell_center.x, cell_center.y, cell_center.z))
# Print the cell corners
cell_corners = grid.cell_corners()[cell_index]
print("Cell corners:")
print("c0:\n" + str(cell_corners.c0))
print("c1:\n" + str(cell_corners.c1))
print("c2:\n" + str(cell_corners.c2))
print("c3:\n" + str(cell_corners.c3))
print("c4:\n" + str(cell_corners.c4))
print("c5:\n" + str(cell_corners.c5))
print("c6:\n" + str(cell_corners.c6))
print("c7:\n" + str(cell_corners.c7))
for (tidx, timestep) in enumerate(time_step_info):
# Read the full SOIL result for time step
soil_results = case.selected_cell_property('DYNAMIC_NATIVE', 'SOIL', tidx)
print("SOIL: {} ({}.{}.{})".format(soil_results[idx], timestep.year, timestep.month, timestep.day))

View File

@@ -0,0 +1,9 @@
######################################################################
# This script applies a cell result to the first view in the project
######################################################################
import rips
resinsight = rips.Instance.find()
view = resinsight.project.views()[0]
view.apply_cell_result(result_type='STATIC_NATIVE', result_variable='DX')

View File

@@ -0,0 +1,18 @@
######################################################################
# This script applies a flow diagnostics cell result to the first view in the project
######################################################################
# Load ResInsight Processing Server Client Library
import rips
# Connect to ResInsight instance
resinsight = rips.Instance.find()
view = resinsight.project.view(view_id=1)
#view.apply_flow_diagnostics_cell_result(result_variable='Fraction',
# selection_mode='FLOW_TR_INJ_AND_PROD')
# Example of setting individual wells. Commented out because well names are case specific.
view.apply_flow_diagnostics_cell_result(result_variable='Fraction',
selection_mode='FLOW_TR_BY_SELECTION',
injectors = ['C-1H', 'C-2H', 'F-2H'],
producers = ['B-1AH', 'B-3H', 'D-1H'])

View File

@@ -0,0 +1,17 @@
######################################################################
# This script sets values for SOIL for all grid cells in the first case in the project
######################################################################
import rips
resinsight = rips.Instance.find()
case = resinsight.project.case(case_id=0)
total_cell_count = case.cell_count().reservoir_cell_count
values = []
for i in range(0, total_cell_count):
values.append(i % 2 * 0.75);
print("Applying values to full grid")
case.set_grid_property(values, 'DYNAMIC_NATIVE', 'SOIL', 0)

View File

@@ -0,0 +1,37 @@
###########################################################################################
# This example will asynchronously calculate the average value for SOIL for all time steps
###########################################################################################
import rips
import itertools
import time
resinsight = rips.Instance.find()
start = time.time()
# Get the case with case id 0
case = resinsight.project.case(case_id=0)
# Get a list of all time steps
timeSteps = case.time_steps()
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.active_cell_property_async('DYNAMIC_NATIVE', 'SOIL', i)
mysum = 0.0
count = 0
# Loop through and append the average. each time we loop resultChunks
# We will trigger a read of the input data, meaning the script will start
# Calculating averages before the whole resultValue for this time step has been received
for chunk in result_chunks:
mysum += sum(chunk.values)
count += len(chunk.values)
averages.append(mysum/count)
end = time.time()
print("Time elapsed: ", end - start)
print(averages)

View File

@@ -0,0 +1,27 @@
###########################################################################################
# This example will synchronously calculate the average value for SOIL for all time steps
###########################################################################################
import rips
import itertools
import time
resinsight = rips.Instance.find()
start = time.time()
# Get the case with case id 0
case = resinsight.project.case(case_id=0)
# Get a list of all time steps
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.active_cell_property('DYNAMIC_NATIVE', 'SOIL', i)
mysum = sum(results)
averages.append(mysum/len(results))
end = time.time()
print("Time elapsed: ", end - start)
print(averages)

View File

@@ -0,0 +1,47 @@
##############################################################################
# This example will create a derived result for each time step asynchronously
##############################################################################
import rips
import time
# Internal function for creating a result from a small chunk of soil and porv results
# The return value of the function is a generator for the results rather than the result itself.
def create_result(soil_chunks, porv_chunks):
for (soil_chunk, porv_chunk) in zip(soil_chunks, porv_chunks):
resultChunk = []
number = 0
for (soil_value, porv_value) in zip(soil_chunk.values, porv_chunk.values):
resultChunk.append(soil_value * porv_value)
# Return a Python generator
yield resultChunk
resinsight = rips.Instance.find()
start = time.time()
case = resinsight.project.cases()[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.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
# ... to match the soil chunks
porv_array = []
for porv_chunk in porv_chunks:
porv_array.append(porv_chunk)
for i in range (0, len(timeStepInfo)):
# Get a generator object for the SOIL property for time step 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.set_active_cell_property_async(result_generator, 'GENERATED', 'SOILPORVAsync', i)
end = time.time()
print("Time elapsed: ", end - start)
print("Transferred all results back")
view = case.views()[0].apply_cell_result('GENERATED', 'SOILPORVAsync')

View File

@@ -0,0 +1,33 @@
##############################################################################
# This example will create a derived result for each time step synchronously
##############################################################################
import rips
import time
resinsight = rips.Instance.find()
start = time.time()
case = resinsight.project.cases()[0]
# Read the full porv result
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.active_cell_property('DYNAMIC_NATIVE', 'SOIL', i)
# Generate the result by looping through both lists in order
results = []
for (soil, porv) in zip(soil_results, porv_results):
results.append(soil * porv)
# Send back result
case.set_active_cell_property(results, 'GENERATED', 'SOILPORVSync', i)
end = time.time()
print("Time elapsed: ", end - start)
print("Transferred all results back")
view = case.views()[0].apply_cell_result('GENERATED', 'SOILPORVSync')

View File

@@ -0,0 +1,14 @@
# Load ResInsight Processing Server Client Library
import rips
# Connect to ResInsight instance
resinsight = rips.Instance.find()
# Example code
# Specific summary case with case_id = 1
summary_case = resinsight.project.summary_case(case_id=1)
summary_case.print_object_info()
# All summary cases
summary_cases = resinsight.project.summary_cases()
for summary_case in summary_cases:
print("Summary case found: ", summary_case.short_name)

View File

@@ -0,0 +1,31 @@
import rips
import time
resinsight = rips.Instance.find()
project = resinsight.project
# Use the following commented lines to import a file from disk
# filename = "path/to/file/1_R001_REEK-0.SMSPEC"
# summary_case = project.import_summary_case(filename)
# Assumes at least one summery case loaded with case_id 1
summary_case = project.summary_case(1)
if summary_case is None:
print("No summary case found")
exit()
vector_name = "FOPT"
summary_data = summary_case.summary_vector_values(vector_name)
print("Data for summary vector " + vector_name)
print(summary_data.values)
time_steps = summary_case.available_time_steps()
print(time_steps.values)
summary_data_sampled = summary_case.resample_values("FOPT", "QUARTER")
print("\nResampled data")
for t, value in zip(summary_data_sampled.time_steps, summary_data_sampled.values):
print(time.strftime("%a, %d %b %Y ", time.gmtime(t)) + " | " + str(value))

View File

@@ -0,0 +1,40 @@
# Load ResInsight Processing Server Client Library
import rips
# Connect to ResInsight instance
resinsight = rips.Instance.find()
print("ResInsight version: " + resinsight.version_string())
# Example code
# get the project
project = resinsight.project
# get the topmost surface folder from the project
surfacefolder = project.surface_folder()
# list of surface files to load
filenames = ["surface1.ts", "surface2.ts", "surface3.ts"]
# Load the files into the top level
for surffile in filenames:
surface = surfacefolder.import_surface(surffile)
if surface is None:
print("Could not import the surface " + surffile)
# add a subfolder
subfolder = surfacefolder.add_folder("ExampleFolder")
# load the same surface multiple times using increasing depth offsets
# store them in the new subfolder we just created
for offset in range(0, 200, 20):
surface = subfolder.import_surface("mysurface.ts")
if surface:
surface.depth_offset = offset
surface.update()
else:
print("Could not import surface.")
# get an existing subfolder
existingfolder = project.surface_folder("ExistingFolder")
if existingfolder is None:
print("Could not find the specified folder.")

View File

@@ -0,0 +1,29 @@
#############################################################
# This example will alter the views of all cases
# By setting the background color and toggle the grid box
# Also clones the first view
#############################################################
import rips
# Connect to ResInsight instance
resinsight = rips.Instance.find()
# Check if connection worked
if resinsight is not None:
# Get a list of all cases
cases = resinsight.project.cases()
for case in cases:
# Get a list of all views
views = case.views()
for view in views:
# Set some parameters for the view
view.show_grid_box = not view.show_grid_box
view.background_color = "#3388AA"
# Update the view in ResInsight
view.update()
# Clone the first view
new_view = views[0].clone()
new_view.background_color = "#FFAA33"
new_view.update()
view.show_grid_box = False
view.set_visible(False)
view.update()

View File

@@ -0,0 +1,18 @@
name = "rips"
import os
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'generated'))
from resinsight_classes import *
from .case import Case, EclipseCase, GeoMechCase
from .grid import Grid
from .instance import Instance
from .pdmobject import PdmObjectBase
from .view import View
from .project import Project
from .plot import Plot, PlotWindow
from .contour_map import EclipseContourMap, GeoMechContourMap
from .well_log_plot import WellLogPlot
from .simulation_well import SimulationWell

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
"""
ResInsight 3d contour map module
"""
import Commands_pb2
from .pdmobject import add_method
from .view import View
from resinsight_classes import EclipseContourMap, GeoMechContourMap
@add_method(EclipseContourMap)
def export_to_text(self, export_file_name='', export_local_coordinates=False, undefined_value_label="NaN", exclude_undefined_values=False):
""" Export snapshot for the current view
Arguments:
export_file_name(str): The file location to store results in.
export_local_coordinates(bool): Should we export local coordinates, or UTM.
undefined_value_label(str): Replace undefined values with this label.
exclude_undefined_values(bool): Skip undefined values.
"""
return self._execute_command(
exportContourMapToText=Commands_pb2.ExportContourMapToTextRequest(
exportFileName=export_file_name,
exportLocalCoordinates=export_local_coordinates,
undefinedValueLabel=undefined_value_label,
excludeUndefinedValues=exclude_undefined_values,
viewId=self.id))
@add_method(GeoMechContourMap)
def export_to_text(self, export_file_name='', export_local_coordinates=False, undefined_value_label="NaN", exclude_undefined_values=False):
""" Export snapshot for the current view
Arguments:
export_file_name(str): The file location to store results in.
export_local_coordinates(bool): Should we export local coordinates, or UTM.
undefined_value_label(str): Replace undefined values with this label.
exclude_undefined_values(bool): Skip undefined values.
"""
return self._execute_command(
exportContourMapToText=Commands_pb2.ExportContourMapToTextRequest(
exportFileName=export_file_name,
exportLocalCoordinates=export_local_coordinates,
undefinedValueLabel=undefined_value_label,
excludeUndefinedValues=exclude_undefined_values,
viewId=self.id))

View File

@@ -0,0 +1,88 @@
# pylint: disable=too-few-public-methods
"""
Module containing the Grid class, containing information
about Case grids.
"""
import Case_pb2
import Grid_pb2
import Grid_pb2_grpc
class Grid:
"""Grid Information. Created by methods in Case
:meth:`rips.case.grid()`
:meth:`rips.case.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.id)
return self.__stub.GetDimensions(
Grid_pb2.GridRequest(case_request=case_request,
grid_index=self.index)).dimensions
def cell_centers_async(self):
"""The cells center for all cells in given grid async.
Returns:
Iterator to a list of Vec3d: class with double attributes x, y, x giving cell centers
"""
case_request = Case_pb2.CaseRequest(id=self.case.id)
chunks = self.__stub.GetCellCenters(
Grid_pb2.GridRequest(case_request=case_request,
grid_index=self.index))
for chunk in chunks:
yield chunk
def cell_centers(self):
"""The cell center for all cells in given grid
Returns:
List of Vec3d: class with double attributes x, y, x giving cell centers
"""
centers = []
chunks = self.cell_centers_async()
for chunk in chunks:
for center in chunk.centers:
centers.append(center)
return centers
def cell_corners_async(self):
"""The cell corners for all cells in given grid, async.
Returns:
iterator to a list of CellCorners: a class with Vec3d for each corner (c0, c1.., c7)
"""
case_request = Case_pb2.CaseRequest(id=self.case.id)
chunks = self.__stub.GetCellCorners(
Grid_pb2.GridRequest(case_request=case_request,
grid_index=self.index))
for chunk in chunks:
yield chunk
def cell_corners(self):
"""The cell corners for all cells in given grid
Returns:
list of CellCorners: a class with Vec3d for each corner (c0, c1.., c7)
"""
corners = []
chunks = self.cell_corners_async()
for chunk in chunks:
for center in chunk.cells:
corners.append(center)
return corners

View File

@@ -0,0 +1,83 @@
"""
Grid Case Group statistics module
"""
from .pdmobject import add_method
from .view import View
from .case import Case
import Commands_pb2
from resinsight_classes import GridCaseGroup
@add_method(GridCaseGroup)
def create_statistics_case(self):
"""Create a Statistics case in the Grid Case Group
Returns:
:class:`rips.generated.resinsight_classes.EclipseCase`
"""
command_reply = self._execute_command(
createStatisticsCase=Commands_pb2.CreateStatisticsCaseRequest(
caseGroupId=self.group_id))
return Case(self.channel,
command_reply.createStatisticsCaseResult.caseId)
@add_method(GridCaseGroup)
def statistics_cases(self):
"""Get a list of all statistics cases in the Grid Case Group
Returns:
List of :class:`rips.generated.resinsight_classes.EclipseCase`
"""
stat_case_collection = self.children("StatisticsCaseCollection")[0]
return stat_case_collection.children("Reservoirs")
@add_method(GridCaseGroup)
def views(self):
"""Get a list of views belonging to a grid case group
Returns:
List of :class:`rips.generated.resinsight_classes.EclipseView`
"""
resinsight_classes = self.descendants(EclipseView)
view_list = []
for pdm_object in resinsight_classes:
view_list.append(pdm_object)
return view_list
@add_method(GridCaseGroup)
def view(self, view_id):
"""Get a particular view belonging to a case group by providing view id
Arguments:
id(int): view id
Returns:
List of :class:`rips.generated.resinsight_classes.EclipseView`
"""
views = self.views()
for view_object in views:
if view_object.id == view_id:
return view_object
return None
@add_method(GridCaseGroup)
def compute_statistics(self, case_ids=None):
""" Compute statistics for the given case ids
Arguments:
case_ids(list of integers): 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=Commands_pb2.ComputeCaseGroupStatRequest(
caseIds=case_ids, caseGroupId=self.group_id))

View File

@@ -0,0 +1,44 @@
import grpc
class RetryOnRpcErrorClientInterceptor(
grpc.UnaryUnaryClientInterceptor, grpc.StreamUnaryClientInterceptor
):
def __init__(
self,
*,
retry_policy,
status_for_retry,
):
self.retry_policy = retry_policy
self.status_for_retry = status_for_retry
def _intercept_call(self, continuation, client_call_details, request_or_iterator):
for retry_num in range(self.retry_policy.num_retries()):
response = continuation(client_call_details, request_or_iterator)
if isinstance(response, grpc.RpcError):
# Return if it was last attempt
if retry_num == (self.retry_policy.num_retries() - 1):
return response
# If status code is not in retryable status codes
if (
self.status_for_retry
and response.code() not in self.status_for_retry
):
return response
self.retry_policy.sleep(retry_num)
else:
return response
def intercept_unary_unary(self, continuation, client_call_details, request):
return self._intercept_call(continuation, client_call_details, request)
def intercept_stream_unary(
self, continuation, client_call_details, request_iterator
):
return self._intercept_call(continuation, client_call_details, request_iterator)

View File

@@ -0,0 +1,336 @@
# 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 App_pb2
import App_pb2_grpc
import Commands_pb2
import Commands_pb2_grpc
from Definitions_pb2 import Empty
import RiaVersionInfo
from .project import Project
from .retry_policy import ExponentialBackoffRetryPolicy
from .grpc_retry_interceptor import RetryOnRpcErrorClientInterceptor
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 __is_valid_port(port):
location = "localhost:" + str(port)
channel = grpc.insecure_channel(location,
options=[
('grpc.enable_http_proxy',
False)
])
app = App_pb2_grpc.AppStub(channel)
try:
app.GetVersion(Empty(), timeout=1)
except grpc.RpcError:
return False
return True
@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
print("Trying port " + str(port))
while Instance.__is_port_in_use(port):
port += 1
print("Trying port " + str(port))
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 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:
print("Got port " + port_env + " from environment")
start_port = int(port_env)
end_port = start_port + 20
for try_port in range(start_port, end_port):
print("Trying port " + str(try_port))
if Instance.__is_port_in_use(try_port) and Instance.__is_valid_port(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(Commands_pb2.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 = Commands_pb2_grpc.CommandsStub(self.channel)
# Main version check package
self.app = App_pb2_grpc.AppStub(self.channel)
self._check_connection_and_version(self.channel, launched)
# Intercept UNAVAILABLE errors and retry on failures
interceptors = (
RetryOnRpcErrorClientInterceptor(
retry_policy=ExponentialBackoffRetryPolicy(min_backoff=100, max_backoff=5000, max_num_retries=20),
status_for_retry=(grpc.StatusCode.UNAVAILABLE,),
),
)
intercepted_channel = grpc.intercept_channel(self.channel, *interceptors)
# Recreate ommand stubs with the retry policy
self.commands = Commands_pb2_grpc.CommandsStub(intercepted_channel)
# Service packages
self.project = Project.create(intercepted_channel)
path = os.getcwd()
self.set_start_dir(path=path)
def _check_connection_and_version(self, channel, launched):
connection_ok = False
version_ok = False
retry_policy = ExponentialBackoffRetryPolicy()
if self.launched:
for num_tries in range(0, retry_policy.num_retries()):
connection_ok, version_ok = self.__check_version()
if connection_ok:
break
retry_policy.sleep(num_tries)
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,
'.', retry_policy.time_out_message())
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())
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=Commands_pb2.FilePathRequest(path=path))
def set_export_folder(self, export_type, path, create_folder=False):
"""
Set the export folder used for all export functions
**Parameters**::
Parameter | Description | Type
---------------- | -------------------------------------------- | -----
export_type | String specifying what to export | String
path | Path to folder | String
create_folder | Create folder if it doesn't exist? | Boolean
**Enum export_type**::
Option | Description
--------------- | ------------
"COMPLETIONS" |
"SNAPSHOTS" |
"PROPERTIES" |
"STATISTICS" |
"""
return self.__execute_command(setExportFolder=Commands_pb2.SetExportFolderRequest(
type=export_type, path=path, createFolder=create_folder))
def set_main_window_size(self, width, height):
"""
Set the main window size in pixels
**Parameters**::
Parameter | Description | Type
--------- | ---------------- | -----
width | Width in pixels | Integer
height | Height in pixels | Integer
"""
return self.__execute_command(setMainWindowSize=Commands_pb2.SetWindowSizeParams(
width=width, height=height))
def set_plot_window_size(self, width, height):
"""
Set the plot window size in pixels
**Parameters**::
Parameter | Description | Type
--------- | ---------------- | -----
width | Width in pixels | Integer
height | Height in pixels | Integer
"""
return self.__execute_command(setPlotWindowSize=Commands_pb2.SetWindowSizeParams(
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')

View File

@@ -0,0 +1,367 @@
# pylint: disable=no-self-use
"""
ResInsight caf::PdmObject connection module
"""
from functools import partial, wraps
import grpc
import re
import builtins
import importlib
import inspect
import sys
import PdmObject_pb2
import PdmObject_pb2_grpc
import Commands_pb2
import Commands_pb2_grpc
import resinsight_classes as ClassList
def camel_to_snake(name):
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
def snake_to_camel(name):
return ''.join(word.title() for word in name.split('_'))
def add_method(cls):
def decorator(func):
setattr(cls, func.__name__, func)
return func # returning func means func can still be used normally
return decorator
def add_static_method(cls):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
setattr(cls, func.__name__, wrapper)
# Note we are not binding func, but wrapper which accepts self but does exactly the same as func
return func # returning func means func can still be used normally
return decorator
class PdmObjectBase:
"""
The ResInsight base class for the Project Data Model
"""
def _execute_command(self, **command_params):
self.__warnings = []
response, call = self._commands.Execute.with_call(
Commands_pb2.CommandParams(**command_params))
for key, value in call.trailing_metadata():
value = value.replace(';;', '\n')
if key == 'warning':
self.__warnings.append(value)
return response
def __init__(self, pb2_object, channel):
self.__warnings = []
self.__chunk_size = 8160
self._channel = channel
# Create stubs
if self._channel:
self._pdm_object_stub = PdmObject_pb2_grpc.PdmObjectServiceStub(self._channel)
self._commands = Commands_pb2_grpc.CommandsStub(self._channel)
if pb2_object is not None:
# Copy parameters from ResInsight
assert(isinstance(pb2_object, PdmObject_pb2.PdmObject))
self._pb2_object = pb2_object
for camel_keyword in self._pb2_object.parameters:
snake_keyword = camel_to_snake(camel_keyword)
setattr(self, snake_keyword, self.__get_grpc_value(camel_keyword))
else:
# Copy parameters from PdmObject defaults
self._pb2_object = PdmObject_pb2.PdmObject(class_keyword=self.__class__.__name__)
self.__copy_to_pb2()
def copy_from(self, object):
"""Copy attribute values from object to self
"""
for attribute in dir(object):
if not attribute.startswith('__'):
value = getattr(object, attribute)
# This is crucial to avoid overwriting methods
if not callable(value):
setattr(self, attribute, value)
if self.__custom_init__ is not None:
self.__custom_init__(self._pb2_object, self._channel)
self.update()
def warnings(self):
return self.__warnings
def has_warnings(self):
return len(self.__warnings) > 0
def __copy_to_pb2(self):
if self._pb2_object is not None:
for snake_kw in dir(self):
if not snake_kw.startswith('_'):
value = getattr(self, snake_kw)
# This is crucial to avoid overwriting methods
if not callable(value):
camel_kw = snake_to_camel(snake_kw)
self.__set_grpc_value(camel_kw, value)
def pb2_object(self):
""" Private method"""
return self._pb2_object
def channel(self):
""" Private method"""
return self._channel
def address(self):
"""Get the unique address of the PdmObject
Returns:
A 64-bit unsigned integer address
"""
return self._pb2_object.address
def set_visible(self, visible):
"""Set the visibility of the object in the ResInsight project tree"""
self._pb2_object.visible = visible
def visible(self):
"""Get the visibility of the object in the ResInsight project tree"""
return self._pb2_object.visible
def print_object_info(self):
"""Print the structure and data content of the PdmObject"""
print("=========== " + self.__class__.__name__ + " =================")
print("Object Attributes: ")
for snake_kw in dir(self):
if not snake_kw.startswith("_") and not callable(getattr(self, snake_kw)):
camel_kw = snake_to_camel(snake_kw)
print(" " + snake_kw + " [" + type(getattr(self, snake_kw)).__name__ +
"]: " + str(getattr(self, snake_kw)))
print("Object Methods:")
for snake_kw in dir(self):
if not snake_kw.startswith("_") and callable(getattr(self, snake_kw)):
print(" " + snake_kw)
def __convert_from_grpc_value(self, value):
if value.lower() == 'false':
return False
if value.lower() == 'true':
return True
try:
int_val = int(value)
return int_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
def __convert_to_grpc_value(self, value):
if isinstance(value, bool):
if value:
return "true"
return "false"
if isinstance(value, PdmObjectBase):
return value.__class__.__name__ + ":" + str(value.address())
if isinstance(value, list):
list_of_values = []
for val in value:
list_of_values.append(self.__convert_to_grpc_value(val))
return "[" + ", ".join(list_of_values) + "]"
return str(value)
def __get_grpc_value(self, camel_keyword):
return self.__convert_from_grpc_value(self._pb2_object.parameters[camel_keyword])
def __set_grpc_value(self, camel_keyword, value):
self._pb2_object.parameters[camel_keyword] = self.__convert_to_grpc_value(value)
def set_value(self, snake_keyword, value):
"""Set the value associated with the provided keyword and updates ResInsight
Arguments:
keyword(str): A string containing the parameter keyword
value(varying): A value matching the type of the parameter.
See keyword documentation and/or print_object_info() to find
the correct data type.
"""
setattr(self, snake_keyword, value)
self.update()
def __islist(self, value):
return value.startswith("[") and value.endswith("]")
def __makelist(self, list_string):
list_string = list_string.lstrip("[")
list_string = list_string.rstrip("]")
strings = list_string.split(", ")
values = []
for string in strings:
values.append(self.__convert_from_grpc_value(string))
return values
def __from_pb2_to_resinsight_classes(self, pb2_object_list, super_class_definition):
pdm_object_list = []
for pb2_object in pb2_object_list:
child_class_definition = ClassList.class_from_keyword(pb2_object.class_keyword)
if child_class_definition is None:
child_class_definition = super_class_definition
pdm_object = child_class_definition(pb2_object=pb2_object, channel=self.channel())
pdm_object_list.append(pdm_object)
return pdm_object_list
def descendants(self, class_definition):
"""Get a list of all project tree descendants matching the class keyword
Arguments:
class_definition[class]: A class definition matching the type of class wanted
Returns:
A list of PdmObjects matching the class_definition
"""
assert(inspect.isclass(class_definition))
class_keyword = class_definition.__name__
try:
request = PdmObject_pb2.PdmDescendantObjectRequest(
object=self._pb2_object, child_keyword=class_keyword)
object_list = self._pdm_object_stub.GetDescendantPdmObjects(
request).objects
return self.__from_pb2_to_resinsight_classes(object_list, class_definition)
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.NOT_FOUND:
return [] # Valid empty result
raise e
def children(self, child_field, class_definition):
"""Get a list of all direct project tree children inside the provided child_field
Arguments:
child_field[str]: A field name
Returns:
A list of PdmObjects inside the child_field
"""
request = PdmObject_pb2.PdmChildObjectRequest(object=self._pb2_object,
child_field=child_field)
try:
object_list = self._pdm_object_stub.GetChildPdmObjects(request).objects
return self.__from_pb2_to_resinsight_classes(object_list, class_definition)
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.NOT_FOUND:
return []
raise e
def ancestor(self, class_definition):
"""Find the first ancestor that matches the provided class_keyword
Arguments:
class_definition[class]: A class definition matching the type of class wanted
"""
assert(inspect.isclass(class_definition))
class_keyword = class_definition.__name__
request = PdmObject_pb2.PdmParentObjectRequest(
object=self._pb2_object, parent_keyword=class_keyword)
try:
pb2_object = self._pdm_object_stub.GetAncestorPdmObject(request)
child_class_definition = ClassList.class_from_keyword(pb2_object.class_keyword)
if child_class_definition is None:
child_class_definition = class_definition
pdm_object = child_class_definition(pb2_object=pb2_object, channel=self.channel())
return pdm_object
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.NOT_FOUND:
return None
raise e
def _call_get_method_async(self, method_name):
request = PdmObject_pb2.PdmObjectGetterRequest(object=self._pb2_object, method=method_name)
for chunk in self._pdm_object_stub.CallPdmObjectGetter(request):
yield chunk
def _call_get_method(self, method_name):
all_values = []
generator = self._call_get_method_async(method_name)
for chunk in generator:
data = getattr(chunk, chunk.WhichOneof('data'))
for value in data.data:
all_values.append(value)
return all_values
def __generate_set_method_chunks(self, array, method_request):
index = -1
while index < len(array):
chunk = PdmObject_pb2.PdmObjectSetterChunk()
if index == -1:
chunk.set_request.CopyFrom(PdmObject_pb2.PdmObjectSetterRequest(
request=method_request, data_count=len(array)))
index += 1
else:
actual_chunk_size = min(len(array) - index + 1, self.__chunk_size)
if isinstance(array[0], float):
chunk.CopyFrom(
PdmObject_pb2.PdmObjectSetterChunk(doubles=PdmObject_pb2.DoubleArray(data=array[index:index +
actual_chunk_size])))
elif isinstance(array[0], int):
chunk.CopyFrom(
PdmObject_pb2.PdmObjectSetterChunk(ints=PdmObject_pb2.IntArray(data=array[index:index +
actual_chunk_size])))
elif isinstance(array[0], str):
chunk.CopyFrom(
PdmObject_pb2.PdmObjectSetterChunk(strings=PdmObject_pb2.StringArray(data=array[index:index +
actual_chunk_size])))
else:
raise Exception("Wrong data type for set method")
index += actual_chunk_size
yield chunk
# Final empty message to signal completion
chunk = PdmObject_pb2.PdmObjectSetterChunk()
yield chunk
def _call_set_method(self, method_name, values):
method_request = PdmObject_pb2.PdmObjectGetterRequest(
object=self._pb2_object, method=method_name)
request_iterator = self.__generate_set_method_chunks(values, method_request)
reply = self._pdm_object_stub.CallPdmObjectSetter(request_iterator)
if reply.accepted_value_count < len(values):
raise IndexError
def _call_pdm_method(self, method_name, **kwargs):
pb2_params = PdmObject_pb2.PdmObject(class_keyword=method_name)
for key, value in kwargs.items():
pb2_params.parameters[snake_to_camel(key)] = self.__convert_to_grpc_value(value)
request = PdmObject_pb2.PdmObjectMethodRequest(
object=self._pb2_object, method=method_name, params=pb2_params)
pb2_object = self._pdm_object_stub.CallPdmObjectMethod(request)
child_class_definition = ClassList.class_from_keyword(pb2_object.class_keyword)
if child_class_definition is None:
return None
pdm_object = child_class_definition(pb2_object=pb2_object, channel=self.channel())
return pdm_object
def update(self):
"""Sync all fields from the Python Object to ResInsight"""
self.__copy_to_pb2()
if self._pdm_object_stub is not None:
self._pdm_object_stub.UpdateExistingPdmObject(self._pb2_object)
else:
raise Exception("Object is not connected to GRPC service so cannot update ResInsight")

View File

@@ -0,0 +1,25 @@
"""
ResInsight 2d plot module
"""
import Commands_pb2
from .pdmobject import PdmObjectBase, add_method
from resinsight_classes import PlotWindow, Plot
@add_method(PlotWindow)
def export_snapshot(self, export_folder='', file_prefix='', output_format='PNG'):
""" Export snapshot for the current plot
Arguments:
export_folder(str): The path to export to. By default will use the global export folder
prefix (str): Exported file name prefix
output_format(str): Enum string. Can be 'PNG' or 'PDF'.
"""
return self._execute_command(
exportSnapshots=Commands_pb2.ExportSnapshotsRequest(type='PLOTS',
prefix=file_prefix,
viewId=self.id,
exportFolder=export_folder,
plotOutputFormat=output_format))

View File

@@ -0,0 +1,393 @@
# pylint: disable=too-many-arguments
# pylint: disable=no-member
"""
The ResInsight project module
"""
import builtins
import grpc
from .case import Case
from .gridcasegroup import GridCaseGroup
from .pdmobject import PdmObjectBase, add_method, add_static_method
from .plot import Plot
from .view import View
import Commands_pb2
from Definitions_pb2 import Empty
import Project_pb2_grpc
import Project_pb2
import PdmObject_pb2
from resinsight_classes import Project, PlotWindow, WellPath, SummaryCase
@add_method(Project)
def __custom_init__(self, pb2_object, channel):
self._project_stub = Project_pb2_grpc.ProjectStub(self._channel)
@add_static_method(Project)
def create(channel):
project_stub = Project_pb2_grpc.ProjectStub(channel)
pb2_object = project_stub.GetPdmObject(Empty())
return Project(pb2_object, channel)
@add_method(Project)
def open(self, path):
"""Open a new project from the given path
Arguments:
path(str): path to project file
"""
self._execute_command(openProject=Commands_pb2.FilePathRequest(path=path))
return self
@add_method(Project)
def save(self, path=""):
"""Save the project to the existing project file, or to a new file
Arguments:
path(str): File path to the file to save the project to. If empty, saves to the active project file
"""
self._execute_command(saveProject=Commands_pb2.SaveProjectRequest(filePath=path))
return self
@add_method(Project)
def close(self):
"""Close the current project (and open new blank project)"""
self._execute_command(closeProject=Empty())
@add_method(Project)
def load_case(self, path):
"""Load a new grid case from the given file path
Arguments:
path(str): file path to case
Returns:
:class:`rips.generated.resinsight_classes.Case`
"""
command_reply = self._execute_command(loadCase=Commands_pb2.FilePathRequest(
path=path))
return self.case(command_reply.loadCaseResult.id)
@add_method(Project)
def selected_cases(self):
"""Get a list of all grid cases selected in the project tree
Returns:
A list of :class:`rips.generated.resinsight_classes.Case`
"""
case_infos = self._project_stub.GetSelectedCases(Empty())
cases = []
for case_info in case_infos.data:
cases.append(self.case(case_info.id))
return cases
@add_method(Project)
def cases(self):
"""Get a list of all grid cases in the project
Returns:
A list of :class:`rips.generated.resinsight_classes.Case`
"""
return self.descendants(Case)
@add_method(Project)
def case(self, case_id):
"""Get a specific grid case from the provided case Id
Arguments:
id(int): case id
Returns:
:class:`rips.generated.resinsight_classes.Case`
"""
allCases = self.cases()
for case in allCases:
if case.id == case_id:
return case
return None
@add_method(Project)
def replace_source_cases(self, grid_list_file, case_group_id=0):
"""Replace all source grid 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=Commands_pb2.ReplaceSourceCasesRequest(
gridListFile=grid_list_file, caseGroupId=case_group_id))
@add_method(Project)
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:
:class:`rips.generated.resinsight_classes.GridCaseGroup`
"""
command_reply = self._execute_command(
createGridCaseGroup=Commands_pb2.CreateGridCaseGroupRequest(
casePaths=case_paths))
return self.grid_case_group(
command_reply.createGridCaseGroupResult.groupId)
@add_method(Project)
def summary_cases(self):
"""Get a list of all summary cases in the Project
Returns: A list of :class:`rips.generated.resinsight_classes.SummaryCase`
"""
return self.descendants(SummaryCase)
@add_method(Project)
def views(self):
"""Get a list of views belonging to a project"""
return self.descendants(View)
@add_method(Project)
def view(self, view_id):
"""Get a particular view belonging to a case by providing view id
Arguments:
view_id(int): view id
Returns:
:class:`rips.generated.resinsight_classes.View`
"""
views = self.views()
for view_object in views:
if view_object.id == view_id:
return view_object
return None
@add_method(Project)
def plots(self):
"""Get a list of all plots belonging to a project
Returns:
List of :class:`rips.generated.resinsight_classes.Plot`
"""
resinsight_classes = self.descendants(PlotWindow)
plot_list = []
for pdm_object in resinsight_classes:
if pdm_object.id != -1:
plot_list.append(pdm_object)
return plot_list
@add_method(Project)
def plot(self, view_id):
"""Get a particular plot by providing view id
Arguments:
view_id(int): view id
Returns:
:class:`rips.generated.resinsight_classes.Plot`
"""
plots = self.plots()
for plot_object in plots:
if plot_object.id == view_id:
return plot_object
return None
@add_method(Project)
def grid_case_groups(self):
"""Get a list of all grid case groups in the project
Returns:
List of :class:`rips.generated.resinsight_classes.GridCaseGroup`
"""
case_groups = self.descendants(GridCaseGroup)
return case_groups
@add_method(Project)
def grid_case_group(self, group_id):
"""Get a particular grid case group belonging to a project
Arguments:
groupId(int): group id
Returns:
:class:`rips.generated.resinsight_classes.GridCaseGroup`
"""
case_groups = self.grid_case_groups()
for case_group in case_groups:
if case_group.group_id == group_id:
return case_group
return None
@add_method(Project)
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=Commands_pb2.ExportMultiCaseRequest(
gridListFile=grid_list_file))
@add_method(Project)
def export_snapshots(self, snapshot_type='ALL', prefix='', plot_format='PNG'):
""" Export all snapshots of a given type
Arguments:
snapshot_type (str): Enum string ('ALL', 'VIEWS' or 'PLOTS')
prefix (str): Exported file name prefix
plot_format(str): Enum string, 'PNG' or 'PDF'
"""
return self._execute_command(
exportSnapshots=Commands_pb2.ExportSnapshotsRequest(
type=snapshot_type, prefix=prefix, caseId=-1, viewId=-1, plotOutputFormat=plot_format))
@add_method(Project)
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=Commands_pb2.ExportWellPathRequest(
wellPathNames=well_paths, mdStepSize=md_step_size))
@add_method(Project)
def scale_fracture_template(self, template_id, half_length, height,
d_factor, conductivity):
""" Scale fracture template parameters
Arguments:
template_id(int): ID of fracture template
half_length (double): Half Length scale factor
height (double): Height scale factor
d_factor (double): D-factor scale factor
conductivity (double): Conductivity scale factor
"""
return self._execute_command(
scaleFractureTemplate=Commands_pb2.ScaleFractureTemplateRequest(
id=template_id,
halfLength=half_length,
height=height,
dFactor=d_factor,
conductivity=conductivity))
@add_method(Project)
def set_fracture_containment(self, template_id, top_layer, base_layer):
""" Set fracture template containment parameters
Arguments:
template_id(int): ID of fracture template
top_layer (int): Top layer containment
base_layer (int): Base layer containment
"""
return self._execute_command(
setFractureContainment=Commands_pb2.SetFracContainmentRequest(
id=template_id, topLayer=top_layer, baseLayer=base_layer))
@add_method(Project)
def import_well_paths(self, well_path_files=None, well_path_folder=''):
""" Import well paths into project
Arguments:
well_path_files(list): List of file paths to import
well_path_folder(str): A folder path containing files to import
Returns:
List of :class:`rips.generated.resinsight_classes.WellPath`
"""
if well_path_files is None:
well_path_files = []
res = self._execute_command(importWellPaths=Commands_pb2.ImportWellPathsRequest(wellPathFolder=well_path_folder,
wellPathFiles=well_path_files))
well_paths = []
for well_path_name in res.importWellPathsResult.wellPathNames:
well_paths.append(self.well_path_by_name(well_path_name))
return well_paths
@add_method(Project)
def well_paths(self):
"""Get a list of all well paths in the project
Returns:
List of :class:`rips.generated.resinsight_classes.WellPath`
"""
return self.descendants(WellPath)
@add_method(Project)
def well_path_by_name(self, well_path_name):
"""Get a specific well path by name from the project
Returns:
:class:`rips.generated.resinsight_classes.WellPath`
"""
all_well_paths = self.well_paths()
for well_path in all_well_paths:
if well_path.name == well_path_name:
return well_path
return None
@add_method(Project)
def import_well_log_files(self, well_log_files=None, well_log_folder=''):
""" Import well log files into project
Arguments:
well_log_files(list): List of file paths to import
well_log_folder(str): A folder path containing files to import
Returns:
A list of well path names (strings) that had logs imported
"""
if well_log_files is None:
well_log_files = []
res = self._execute_command(importWellLogFiles=Commands_pb2.ImportWellLogFilesRequest(wellLogFolder=well_log_folder,
wellLogFiles=well_log_files))
return res.importWellLogFilesResult.wellPathNames
@add_method(Project)
def import_formation_names(self, formation_files=None):
""" Import formation names into project
Arguments:
formation_files(list): list of files to import
"""
if formation_files is None:
formation_files = []
elif isinstance(formation_files, str):
formation_files = [formation_files]
self._execute_command(importFormationNames=Commands_pb2.ImportFormationNamesRequest(formationFiles=formation_files,
applyToCaseId=-1))

View File

@@ -0,0 +1,83 @@
import abc
import time
import random
class RetryPolicy(abc.ABC):
@abc.abstractmethod
def sleep(self, retry_num):
"""
How long to sleep in milliseconds.
:param retry_num: the number of retry (starting from zero)
"""
assert retry_num >= 0
@abc.abstractmethod
def time_out_message(self):
"""
Generate a error message for user on time out.
"""
pass
@abc.abstractmethod
def num_retries(self):
"""
Max number retries.
"""
pass
class FixedRetryPolicy(RetryPolicy):
def __init__(self, sleep_time=1000, max_num_retries=10):
"""
Create a fixed time retry policy.
:param sleep_time: time to sleep in milliseconds.
:param max_num_retries: max number of retries.
"""
self.sleep_time = sleep_time
self.max_num_retries = max_num_retries
def sleep(self, retry_num):
time.sleep(self.sleep_time / 1000)
def time_out_message(self):
return "Tried {} times with {} milliseconds apart.".format(
self.max_num_retries, self.sleep_time
)
def num_retries(self):
return self.max_num_retries
class ExponentialBackoffRetryPolicy(RetryPolicy):
def __init__(self, min_backoff=200, max_backoff=10000, max_num_retries=20):
"""
Create a truncated exponential backoff policy.
See: https://en.wikipedia.org/wiki/Exponential_backoff
:param min_backoff: minimum time to sleep in milliseconds.
:param max_backoff: maximum time to sleep in milliseconds.
:param max_num_retries: max number of retries.
"""
self.min_backoff = min_backoff
self.max_backoff = max_backoff
self.max_num_retries = max_num_retries
self.multiplier = 2
def sleep(self, retry_num):
# Add a random component to avoid synchronized retries
wiggle = random.randint(0, 100)
sleep_ms = min(
self.min_backoff + self.multiplier ** retry_num + wiggle, self.max_backoff
)
time.sleep(sleep_ms / 1000)
def time_out_message(self):
return (
"Tried {} times with increasing delay (from {} to {} milliseconds).".format(
self.max_num_retries, self.min_backoff, self.max_backoff
)
)
def num_retries(self):
return self.max_num_retries

View File

@@ -0,0 +1,74 @@
"""
ResInsight SimulationWell
"""
import grpc
import SimulationWell_pb2
import SimulationWell_pb2_grpc
import Properties_pb2
import Properties_pb2_grpc
from resinsight_classes import SimulationWell
from .pdmobject import PdmObjectBase, add_method
import rips.case
@add_method(SimulationWell)
def __custom_init__(self, pb2_object, channel):
self._simulation_well_stub = SimulationWell_pb2_grpc.SimulationWellStub(channel)
@add_method(SimulationWell)
def status(self, timestep):
"""Get simulation well status
**SimulationWellStatus class description**::
Parameter | Description | Type
----------- | ------------------------------------------------------------- | -----
well_type | Well type as string | string
is_open | True if simulation well is open at the specified time step | bool
Arguments:
timestep(int): Time step index
"""
sim_well_request = SimulationWell_pb2.SimulationWellRequest(case_id=self.case().id,
well_name=self.name,
timestep=timestep)
return self._simulation_well_stub.GetSimulationWellStatus(sim_well_request)
@add_method(SimulationWell)
def cells(self, timestep):
"""Get reservoir cells the simulation well is defined for
**SimulationWellCellInfo class description**::
Parameter | Description | Type
----------- | --------------------------------------------------------- | -----
ijk | Cell IJK location | Vec3i
grid_index | Grid index | int
is_open | True if connection to is open at the specified time step | bool
branch_id | | int
segment_id | | int
Arguments:
timestep(int): Time step index
Returns:
List of SimulationWellCellInfo
"""
sim_well_request = SimulationWell_pb2.SimulationWellRequest(case_id=self.case().id,
well_name=self.name,
timestep=timestep)
return self._simulation_well_stub.GetSimulationWellCells(sim_well_request).data
@add_method(SimulationWell)
def case(self):
return self.ancestor(rips.case.Case)

View File

@@ -0,0 +1,49 @@
import pytest
import sys
import os
import getopt
sys.path.insert(1, os.path.join(sys.path[0], '../../'))
import rips
_rips_instance = None
@pytest.fixture
def rips_instance():
return _rips_instance
@pytest.fixture
def initialize_test():
_rips_instance.project.close() # make sure ResInsight is clean before execution of test
yield initialize_test
_rips_instance.project.close() # make sure ResInsight is clean after test
def pytest_addoption(parser):
parser.addoption("--console", action="store_true", default=False,
help="Run as console application")
parser.addoption("--existing", action="store_true", default=False,
help="Look for existing ResInsight")
def pytest_configure(config):
global _rips_instance
console = False
if config.getoption('--existing'):
print("Looking for existing ResInsight")
_rips_instance = rips.Instance.find()
else:
if config.getoption('--console'):
console = True
_rips_instance = rips.Instance.launch(console=console)
if not _rips_instance:
print("Need a valid ResInsight executable to launch tests")
exit(0)
def pytest_unconfigure(config):
if not config.getoption('--existing'):
if _rips_instance:
_rips_instance.exit()

View File

@@ -0,0 +1,3 @@
# The path here is intended to be used when pytest is launced from the source tree of the ResInsight repository
# This enables use of test datasets from the TestModels folder
PATH = "../../../../TestModels"

View File

@@ -0,0 +1,205 @@
import sys
import os
import math
import pytest
import grpc
import tempfile
sys.path.insert(1, os.path.join(sys.path[0], '../../'))
import rips
import dataroot
def test_Launch(rips_instance, initialize_test):
assert(rips_instance is not None)
def test_EmptyProject(rips_instance, initialize_test):
cases = rips_instance.project.cases()
assert(len(cases) is 0)
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)
cases = rips_instance.project.cases()
assert(len(cases) is 1)
def test_BoundingBox(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")
boundingbox = case.reservoir_boundingbox()
assert(math.isclose(3382.90, boundingbox.min_x, abs_tol=1.0e-1))
assert(math.isclose(5850.48, boundingbox.max_x, abs_tol=1.0e-1))
assert(math.isclose(4157.45, boundingbox.min_y, abs_tol=1.0e-1))
assert(math.isclose(7354.93, boundingbox.max_y, abs_tol=1.0e-1))
assert(math.isclose(-4252.61, boundingbox.min_z, abs_tol=1.0e-1))
assert(math.isclose(-4103.60, boundingbox.max_z, abs_tol=1.0e-1))
min_depth, max_depth = case.reservoir_depth_range()
assert(math.isclose(4103.60, min_depth, abs_tol=1.0e-1))
assert(math.isclose(4252.61, max_depth, abs_tol=1.0e-1))
def test_MultipleCases(rips_instance, initialize_test):
case_paths = []
case_paths.append(dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID")
case_paths.append(dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID")
case_paths.append(dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID")
case_names = []
for case_path in case_paths:
case_name = os.path.splitext(os.path.basename(case_path))[0]
case_names.append(case_name)
rips_instance.project.load_case(path=case_path)
cases = rips_instance.project.cases()
assert(len(cases) == len(case_names))
for i, case_name in enumerate(case_names):
assert(case_name == cases[i].name)
def get_cell_index_with_ijk(cell_info, i, j, k):
for (idx, cell) in enumerate(cell_info):
if cell.local_ijk.i == i and cell.local_ijk.j == j and cell.local_ijk.k == k:
return idx
return -1
def check_corner(actual, expected):
assert(math.isclose(actual.x, expected[0], abs_tol=0.1))
assert(math.isclose(actual.y, expected[1], abs_tol=0.1))
assert(math.isclose(actual.z, expected[2], abs_tol=0.1))
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(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)
time_steps = case.time_steps()
assert(len(time_steps) == 9)
days_since_start = case.days_since_start()
assert(len(days_since_start) == 9)
cell_info = case.cell_info_for_active_cells()
assert(len(cell_info) == cell_count_info.active_cell_count)
# Check an active cell (found in resinsight ui)
cell_index = get_cell_index_with_ijk(cell_info, 23, 44, 19)
assert(cell_index != -1)
cell_centers = case.active_cell_centers()
assert(len(cell_centers) == cell_count_info.active_cell_count)
# Check the cell center for the specific cell
assert(math.isclose(3627.17, cell_centers[cell_index].x, abs_tol=0.1))
assert(math.isclose(5209.75, cell_centers[cell_index].y, abs_tol=0.1))
assert(math.isclose(4179.6, cell_centers[cell_index].z, abs_tol=0.1))
cell_corners = case.active_cell_corners()
assert(len(cell_corners) == cell_count_info.active_cell_count)
# Expected values from ResInsight UI
expected_corners = [[3565.22, 5179.02, 4177.18],
[3655.67, 5145.34, 4176.63],
[3690.07, 5240.69, 4180.02],
[3599.87, 5275.16, 4179.32],
[3564.13, 5178.61, 4179.75],
[3654.78, 5144.79, 4179.23],
[3688.99, 5239.88, 4182.7],
[3598.62, 5274.48, 4181.96]]
check_corner(cell_corners[cell_index].c0, expected_corners[0])
check_corner(cell_corners[cell_index].c1, expected_corners[1])
check_corner(cell_corners[cell_index].c2, expected_corners[2])
check_corner(cell_corners[cell_index].c3, expected_corners[3])
check_corner(cell_corners[cell_index].c4, expected_corners[4])
check_corner(cell_corners[cell_index].c5, expected_corners[5])
check_corner(cell_corners[cell_index].c6, expected_corners[6])
check_corner(cell_corners[cell_index].c7, expected_corners[7])
# No coarsening info for this case
coarsening_info = case.coarsening_info()
assert(len(coarsening_info) == 0)
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.address() is not 0)
assert(case.__class__.__name__ == "EclipseCase")
@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(len(case.grids()) == 1)
cellCountInfo = case.cell_count()
assert(cellCountInfo.active_cell_count == 43374)
assert(cellCountInfo.reservoir_cell_count == 60048)
time_steps = case.time_steps()
assert(len(time_steps) == 11)
days_since_start = case.days_since_start()
assert(len(days_since_start) == 11)
@pytest.mark.skipif(sys.platform.startswith('linux'), reason="Brugge is currently exceptionally slow on Linux")
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(case_id=0)
assert(case is not None)
assert(case.name == "TEST10K_FLT_LGR_NNC")
assert(case.id == 0)
cases = rips_instance.project.cases()
assert(len(cases) is 1)
case.replace(new_grid_file=case_path)
# Check that the case object has been changed
assert(case.name == "BRUGGE_0000")
assert(case.id == 0)
cases = rips_instance.project.cases()
assert(len(cases) is 1)
# Check that retrieving the case object again will yield the changed object
case = project.case(case_id=0)
assert(case.name == "BRUGGE_0000")
assert(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)
def test_selected_cells(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")
selected_cells = case.selected_cells()
assert(len(selected_cells) == 0)
time_step_info = case.time_steps()
for (tidx, timestep) in enumerate(time_step_info):
# Try to read for SOIL the time step (will be empty since nothing is selected)
soil_results = case.selected_cell_property('DYNAMIC_NATIVE', 'SOIL', tidx)
assert(len(soil_results) == 0)

View File

@@ -0,0 +1,10 @@
import sys
import os
import tempfile
import pytest
import grpc
sys.path.insert(1, os.path.join(sys.path[0], '../../'))
import rips
import dataroot

View File

@@ -0,0 +1,55 @@
import sys
import os
import math
sys.path.insert(1, os.path.join(sys.path[0], '../../'))
import rips
import dataroot
def check_corner(actual, expected):
assert(math.isclose(actual.x, expected[0], abs_tol=0.1))
assert(math.isclose(actual.y, expected[1], abs_tol=0.1))
assert(math.isclose(actual.z, expected[2], abs_tol=0.1))
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(len(case.grids()) == 2)
grid = case.grid(index=0)
dimensions = grid.dimensions()
assert(dimensions.i == 90)
assert(dimensions.j == 96)
assert(dimensions.k == 36)
cell_centers = grid.cell_centers()
assert(len(cell_centers) == (dimensions.i * dimensions.j * dimensions.k))
# Test a specific cell (results from ResInsight UI)
cell_index = 168143
assert(math.isclose(3627.17, cell_centers[cell_index].x, abs_tol=0.1))
assert(math.isclose(5209.75, cell_centers[cell_index].y, abs_tol=0.1))
assert(math.isclose(4179.6, cell_centers[cell_index].z, abs_tol=0.1))
cell_corners = grid.cell_corners()
assert(len(cell_corners) == (dimensions.i * dimensions.j * dimensions.k))
# Expected values from ResInsight UI
expected_corners = [[3565.22, 5179.02, 4177.18],
[3655.67, 5145.34, 4176.63],
[3690.07, 5240.69, 4180.02],
[3599.87, 5275.16, 4179.32],
[3564.13, 5178.61, 4179.75],
[3654.78, 5144.79, 4179.23],
[3688.99, 5239.88, 4182.7],
[3598.62, 5274.48, 4181.96]]
check_corner(cell_corners[cell_index].c0, expected_corners[0])
check_corner(cell_corners[cell_index].c1, expected_corners[1])
check_corner(cell_corners[cell_index].c2, expected_corners[2])
check_corner(cell_corners[cell_index].c3, expected_corners[3])
check_corner(cell_corners[cell_index].c4, expected_corners[4])
check_corner(cell_corners[cell_index].c5, expected_corners[5])
check_corner(cell_corners[cell_index].c6, expected_corners[6])
check_corner(cell_corners[cell_index].c7, expected_corners[7])

View File

@@ -0,0 +1,74 @@
import sys
import os
import grpc
import pytest
import rips.generated.NNCProperties_pb2 as NNCProperties_pb2
sys.path.insert(1, os.path.join(sys.path[0], '../../'))
import rips
import dataroot
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)
properties = case.available_nnc_properties()
assert(len(properties) == 1)
assert("TRAN" == properties[0].name)
assert(NNCProperties_pb2.NNCPropertyType.Value('NNC_STATIC') == properties[0].property_type)
nnc_connections = case.nnc_connections()
assert(len(nnc_connections) == 3627)
connection = nnc_connections[0]
assert(connection.cell1.i == 33)
assert(connection.cell1.j == 40)
assert(connection.cell1.k == 14)
assert(connection.cell_grid_index1 == 0)
tran_vals = case.nnc_connections_static_values("TRAN")
assert(len(tran_vals) == len(nnc_connections))
for t in tran_vals:
assert(isinstance(t, float))
# Generate some data
new_data = []
for (c, _) in enumerate(nnc_connections):
new_data.append(float(c))
property_name = "NEW_PROP"
case.set_nnc_connections_values(new_data, property_name, 0)
new_prop_vals = case.nnc_connections_generated_values(property_name, 0)
assert(len(new_prop_vals) == len(new_data))
for i in range(0, len(new_data)):
assert(new_data[i] == new_prop_vals[i])
# Set some other data for second time step
for i in range(0, len(new_data)):
new_data[i] = new_data[i] * 2.0
case.set_nnc_connections_values(new_data, property_name, 1)
new_prop_vals = case.nnc_connections_generated_values(property_name, 1)
assert(len(new_prop_vals) == len(nnc_connections))
for i in range(0, len(new_data)):
assert(new_data[i] == new_prop_vals[i])
def test_non_existing_dynamic_values(rips_instance, initialize_test):
casePath = dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID"
case = rips_instance.project.load_case(path=casePath)
with pytest.raises(grpc.RpcError):
case.nnc_connections_dynamic_values("x", 0)
def test_invalid_time_steps(rips_instance, initialize_test):
casePath = dataroot.PATH + "/TEST10K_FLT_LGR_NNC/TEST10K_FLT_LGR_NNC.EGRID"
case = rips_instance.project.load_case(path=casePath)
with pytest.raises(grpc.RpcError):
case.nnc_connections_generated_values("Formation Allan", 9999)

View File

@@ -0,0 +1,75 @@
import sys
import os
import pytest
import grpc
import tempfile
sys.path.insert(1, os.path.join(sys.path[0], '../../'))
import rips
import dataroot
def test_loadProject(rips_instance, initialize_test):
project = rips_instance.project.open(dataroot.PATH + "/TEST10K_FLT_LGR_NNC/10KWithWellLog.rsp")
case = project.cases()[0]
assert(case is not None)
assert(case.name == "TEST10K_FLT_LGR_NNC")
assert(case.id == 0)
cases = rips_instance.project.cases()
assert(len(cases) is 1)
def test_well_log_plots(rips_instance, initialize_test):
project = rips_instance.project.open(dataroot.PATH + "/TEST10K_FLT_LGR_NNC/10KWithWellLog.rsp")
plots = project.plots()
well_log_plots = []
for plot in plots:
if isinstance(plot, rips.WellLogPlot):
assert(plot.depth_type == "MEASURED_DEPTH")
well_log_plots.append(plot)
assert(len(well_log_plots) == 2)
with tempfile.TemporaryDirectory(prefix="rips") as tmpdirname:
for well_log_plot in well_log_plots:
well_log_plot.depth_type = "TRUE_VERTICAL_DEPTH_RKB"
well_log_plot.update()
if rips_instance.is_gui():
well_log_plot.export_snapshot(tmpdirname)
well_log_plot.export_data_as_las(tmpdirname)
files = os.listdir(tmpdirname)
print(files)
if rips_instance.is_gui():
assert(len(files) == 4)
else:
assert(len(files) == 2)
plots2 = project.plots()
for plot2 in plots2:
if isinstance(plot2, rips.WellLogPlot):
assert(plot2.depth_type == "TRUE_VERTICAL_DEPTH_RKB")
@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')

View File

@@ -0,0 +1,112 @@
import sys
import os
import grpc
import pytest
import tempfile
sys.path.insert(1, os.path.join(sys.path[0], '../../'))
import rips
import dataroot
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.active_cell_property_async('DYNAMIC_NATIVE', 'SOIL', 1)
mysum = 0.0
count = 0
for chunk in resultChunks:
mysum += sum(chunk.values)
count += len(chunk.values)
average = mysum / count
assert(mysum == pytest.approx(621.768, abs=0.001))
assert(average != pytest.approx(0.0158893, abs=0.0000001))
assert(average == pytest.approx(0.0558893, abs=0.0000001))
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.active_cell_property('DYNAMIC_NATIVE', 'SOIL', 1)
mysum = sum(results)
average = mysum / len(results)
assert(mysum == pytest.approx(621.768, abs=0.001))
assert(average != pytest.approx(0.0158893, abs=0.0000001))
assert(average == pytest.approx(0.0558893, abs=0.0000001))
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.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.active_cell_property('DYNAMIC_NATIVE', 'SOIL', 1)
results.append(5.0)
with pytest.raises(grpc.RpcError):
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.active_cell_property('DYNAMIC_NATIVE', 'SOIL', 1)
case.chunk_size = len(results)
results.append(5.0)
with pytest.raises(IndexError):
assert case.set_active_cell_property(results, 'GENERATED', 'SOIL', 1)
def createResult(poroChunks, permxChunks):
for (poroChunk, permxChunk) in zip(poroChunks, permxChunks):
resultChunk = []
for (poro, permx) in zip(poroChunk.values, permxChunk.values):
resultChunk.append(poro * permx)
yield resultChunk
def checkResults(poroValues, permxValues, poropermxValues):
for (poro, permx, poropermx) in zip(poroValues, permxValues, poropermxValues):
recalc = poro * permx
assert(recalc == pytest.approx(poropermx, rel=1.0e-10))
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.active_cell_property_async('STATIC_NATIVE', 'PORO', 0)
permxChunks = case.active_cell_property_async('STATIC_NATIVE', 'PERMX', 0)
case.set_active_cell_property_async(createResult(
poroChunks, permxChunks), '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)
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.cases()[0]
view = case.views()[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))

View File

@@ -0,0 +1,51 @@
import sys
import os
sys.path.insert(1, os.path.join(sys.path[0], '../../'))
import rips
import dataroot
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(len(case.grids()) == 2)
cell_count_info = case.cell_count()
sim_wells = case.simulation_wells()
assert(len(sim_wells) == 3)
assert(sim_wells[0].name == "GI1")
assert(sim_wells[1].name == "GP1")
assert(sim_wells[2].name == "GP2")
timesteps = case.time_steps()
# On time step 0 all simulation wells are undefined
for sim_well in sim_wells:
status = sim_well.status(0)
assert(status.well_type == "NotDefined")
# On time step 3 all wells are producing
for sim_well in sim_wells:
status = sim_well.status(3)
assert(status.well_type == "Producer")
# On time step 0 all simulation wells have no cells
for sim_well in sim_wells:
cells = sim_well.cells(0)
assert(len(cells) == 0)
# On the other time steps there should be cells
expected_cell_count = {}
expected_cell_count["GP1"] = 105
expected_cell_count["GI1"] = 38
expected_cell_count["GP2"] = 18
for sim_well in sim_wells:
for (tidx, timestep) in enumerate(timesteps):
if (tidx > 0):
cells = sim_well.cells(tidx)
print("well: " + sim_well.name + " timestep: " +
str(tidx) + " cells:" + str(len(cells)))
assert(len(cells) == expected_cell_count[sim_well.name])

View File

@@ -0,0 +1,115 @@
import sys
import os
import math
import contextlib
import os
import shutil
import tempfile
sys.path.insert(1, os.path.join(sys.path[0], '../../'))
import rips
import dataroot
def test_summary_import_and_find(rips_instance, initialize_test):
casePath = dataroot.PATH + "/flow_diagnostics_test/SIMPLE_SUMMARY2.SMSPEC"
summary_case = rips_instance.project.import_summary_case(casePath)
assert(summary_case.id == 1)
case_id = 234
found_summary_case = rips_instance.project.summary_case(case_id)
assert(found_summary_case is None)
correct_case_id = 1
found_summary_case = rips_instance.project.summary_case(correct_case_id)
assert(found_summary_case is not None)
rips_instance.project.close()
correct_case_id = 1
found_summary_case = rips_instance.project.summary_case(correct_case_id)
assert(found_summary_case is None)
def test_summary_data(rips_instance, initialize_test):
casePath = dataroot.PATH + "/flow_diagnostics_test/SIMPLE_SUMMARY2.SMSPEC"
summary_case = rips_instance.project.import_summary_case(casePath)
assert(summary_case.id == 1)
addresses = summary_case.available_addresses()
assert(len(addresses.values) == 343)
summary_data = summary_case.summary_vector_values("FOPT")
assert(len(summary_data.values) == 60)
def test_summary_resample(rips_instance, initialize_test):
casePath = dataroot.PATH + "/flow_diagnostics_test/SIMPLE_SUMMARY2.SMSPEC"
summary_case = rips_instance.project.import_summary_case(casePath)
assert(summary_case.id == 1)
summary_data_sampled = summary_case.resample_values("FOPT", "NONE")
assert(len(summary_data_sampled.values) == 60)
assert(len(summary_data_sampled.time_steps) == 60)
summary_data_sampled = summary_case.resample_values("FOPT", "DAY")
assert(len(summary_data_sampled.values) == 721)
assert(len(summary_data_sampled.time_steps) == 721)
summary_data_sampled = summary_case.resample_values("FOPT", "MONTH")
assert(len(summary_data_sampled.values) == 24)
assert(len(summary_data_sampled.time_steps) == 24)
summary_data_sampled = summary_case.resample_values("FOPT", "QUARTER")
assert(len(summary_data_sampled.values) == 8)
assert(len(summary_data_sampled.time_steps) == 8)
summary_data_sampled = summary_case.resample_values("FOPT", "YEAR")
assert(len(summary_data_sampled.values) == 3)
assert(len(summary_data_sampled.time_steps) == 3)
@contextlib.contextmanager
def cd(newdir, cleanup=lambda: True):
prevdir = os.getcwd()
os.chdir(os.path.expanduser(newdir))
try:
yield
finally:
os.chdir(prevdir)
cleanup()
@contextlib.contextmanager
def tempdir():
dirpath = tempfile.mkdtemp()
def cleanup():
shutil.rmtree(dirpath)
with cd(dirpath, cleanup):
yield dirpath
# This test ensures that missing unsmry file is handeled gracefully
def test_summary_no_unsmry(rips_instance, initialize_test):
casePathRelative = dataroot.PATH + "/flow_diagnostics_test/SIMPLE_SUMMARY2.SMSPEC"
# create an absolute path, as the helper functions used to create a temporary folder does not work
# with the relative (..\..\) part of the file path
casePath = os.path.abspath(casePathRelative)
with tempdir() as dirpath:
base_path = os.path.basename(casePath)
temp_path = os.path.join(dirpath, base_path)
shutil.copy2(casePath, temp_path)
summary_case = rips_instance.project.import_summary_case(temp_path)
values = summary_case.summary_vector_values()
assert(len(values.values) == 1)
time_steps = summary_case.available_time_steps()
assert(len(time_steps.values) == 1)
addresses = summary_case.available_addresses()
assert(len(addresses.values) == 1)
summary_case.resample_values()

View File

@@ -0,0 +1,20 @@
import sys
import os
sys.path.insert(1, os.path.join(sys.path[0], '../../'))
import rips
import dataroot
def test_10k(rips_instance, initialize_test):
case_root_path = dataroot.PATH + "/TEST10K_FLT_LGR_NNC"
case_path = case_root_path + "/TEST10K_FLT_LGR_NNC.EGRID"
case = rips_instance.project.load_case(path=case_path)
assert(len(case.grids()) == 2)
well_path_files = [case_root_path + "/wellpath_a.dev", case_root_path + "/wellpath_b.dev"]
well_path_names = rips_instance.project.import_well_paths(well_path_files)
wells = rips_instance.project.well_paths()
assert(len(wells) == 2)
assert(wells[0].name == "Well Path A")
assert(wells[1].name == "Well Path B")

View File

@@ -0,0 +1,201 @@
"""
ResInsight 3d view module
"""
import builtins
import Commands_pb2 as Cmd
import rips.case # Circular import of Case, which already imports View. Use full name.
from .pdmobject import add_method
from resinsight_classes import View, ViewWindow, EclipseView, GeoMechView
@add_method(View)
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
- STATIC_NATIVE
- SOURSIMRL
- GENERATED
- INPUT_PROPERTY
- FORMATION_NAMES
- FLOW_DIAGNOSTICS
- INJECTION_FLOODING
result_variable (str): String representing the result variable.
"""
cell_result = self.cell_result()
cell_result.result_type = result_type
cell_result.result_variable = result_variable
cell_result.update()
@add_method(View)
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
**Parameters**::
Parameter | Description | Type
------------------- | ------------------------------------------------------ | -----
result_variable | String representing the result value | String
selection_mode | String specifying which tracers to select | String
injectors | List of injector names, used by 'FLOW_TR_BY_SELECTION' | String List
producers | List of injector names, used by 'FLOW_TR_BY_SELECTION' | String List
**Enum compdat_export**::
Option | Description
------------------------| ------------
"TOF" | Time of flight
"Fraction" | Fraction
"MaxFractionTracer" | Max Fraction Tracer
"Communication" | Communication
"""
if injectors is None:
injectors = []
if producers is None:
producers = []
cell_result = self.cell_result()
cell_result.result_type = "FLOW_DIAGNOSTICS"
cell_result.result_variable = result_variable
cell_result.flow_tracer_selection_mode = selection_mode
if selection_mode == 'FLOW_TR_BY_SELECTION':
cell_result.selected_injector_tracers = injectors
cell_result.selected_producer_tracers = producers
cell_result.update()
@add_method(View)
def clone(self):
"""Clone the current view"""
view_id = self._execute_command(cloneView=Cmd.CloneViewRequest(
viewId=self.id)).createViewResult.viewId
return self.case().view(view_id)
@add_method(View)
def set_time_step(self, time_step):
"""Set the time step for current view"""
case_id = self.case().id
return self._execute_command(setTimeStep=Cmd.SetTimeStepParams(
caseId=case_id, viewId=self.id, timeStep=time_step))
@add_method(View)
def export_sim_well_fracture_completions(self, time_step,
simulation_well_names, file_split,
compdat_export):
"""Export fracture completions for simulation wells
**Parameters**::
Parameter | Description | Type
----------------------------| ------------------------------------------------ | -----
time_step | Time step to export for | Integer
simulation_well_names | List of simulation well names | List
file_split | Controls how export data is split into files | String enum
compdat_export | Compdat export type | String enum
**Enum file_split**::
Option | Description
----------------------------------- | ------------
"UNIFIED_FILE" <b>Default Option</b>| A single file with all transmissibilities
"SPLIT_ON_WELL" | One file for each well transmissibilities
"SPLIT_ON_WELL_AND_COMPLETION_TYPE" | One file for each completion type for each well
**Enum compdat_export**::
Option | Description
-----------------------------------------| ------------
"TRANSMISSIBILITIES"<b>Default Option</b>| Direct export of transmissibilities
"WPIMULT_AND_DEFAULT_CONNECTION_FACTORS" | Include export of WPIMULT
"""
if isinstance(simulation_well_names, str):
simulation_well_names = [simulation_well_names]
case_id = self.case().id
return self._execute_command(
exportSimWellFractureCompletions=Cmd.ExportSimWellPathFracRequest(
caseId=case_id,
viewId=self.id,
timeStep=time_step,
simulationWellNames=simulation_well_names,
fileSplit=file_split,
compdatExport=compdat_export))
@add_method(View)
def export_visible_cells(self,
export_keyword='FLUXNUM',
visible_active_cells_value=1,
hidden_active_cells_value=0,
inactive_cells_value=0):
"""Export special properties for all visible cells.
Arguments:
export_keyword (string): The keyword to export.
Choices: 'FLUXNUM' or 'MULTNUM'. Default: 'FLUXNUM'
visible_active_cells_value (int): Value to export forvisible active cells. Default: 1
hidden_active_cells_value (int): Value to export for hidden active cells. Default: 0
inactive_cells_value (int): Value to export for inactive cells. Default: 0
"""
case_id = self.case().id
return self._execute_command(
exportVisibleCells=Cmd.ExportVisibleCellsRequest(
caseId=case_id,
viewId=self.id,
exportKeyword=export_keyword,
visibleActiveCellsValue=visible_active_cells_value,
hiddenActiveCellsValue=hidden_active_cells_value,
inactiveCellsValue=inactive_cells_value))
@add_method(View)
def export_property(self, undefined_value=0.0):
""" Export the current Eclipse property from the view
Arguments:
undefined_value (double): Value to use for undefined values. Defaults to 0.0
"""
case_id = self.case().id
return self._execute_command(
exportPropertyInViews=Cmd.ExportPropertyInViewsRequest(
caseId=case_id,
viewIds=[self.id],
undefinedValue=undefined_value))
@add_method(ViewWindow)
def case(self):
"""Get the case the view belongs to"""
mycase = self.ancestor(rips.case.Case)
assert(mycase is not None)
return mycase
@add_method(ViewWindow)
def export_snapshot(self, prefix='', export_folder=''):
""" Export snapshot for the current view
Arguments:
prefix (str): Exported file name prefix
export_folder(str): The path to export to. By default will use the global export folder
"""
case_id = self.case().id
return self._execute_command(
exportSnapshots=Cmd.ExportSnapshotsRequest(type='VIEWS',
prefix=prefix,
caseId=case_id,
viewId=self.id,
exportFolder=export_folder))

View File

@@ -0,0 +1,56 @@
"""
ResInsight Well Log Plot plot module
"""
import Commands_pb2
from .plot import Plot
from .pdmobject import PdmObjectBase, add_method
from resinsight_classes import WellLogPlot
@add_method(WellLogPlot)
def export_data_as_las(self, export_folder, file_prefix='', export_tvdrkb=False, capitalize_file_names=False, resample_interval=0.0, convert_to_standard_units=False):
""" Export LAS file(s) for the current plot
Arguments:
export_folder(str): The path to export to. By default will use the global export folder
file_prefix (str): Exported file name prefix
export_tvdrkb(bool): Export in TVD-RKB format
capitalize_file_names(bool): Make all file names upper case
resample_interval(double): if > 0.0 the files will be resampled
Returns:
A list of files exported
"""
res = self._execute_command(exportWellLogPlotData=Commands_pb2.ExportWellLogPlotDataRequest(exportFormat='LAS',
viewId=self.id,
exportFolder=export_folder,
filePrefix=file_prefix,
exportTvdRkb=export_tvdrkb,
capitalizeFileNames=capitalize_file_names,
resampleInterval=resample_interval,
convertCurveUnits=convert_to_standard_units))
return res.exportWellLogPlotDataResult.exportedFiles
@add_method(WellLogPlot)
def export_data_as_ascii(self, export_folder, file_prefix='', capitalize_file_names=False):
""" Export LAS file(s) for the current plot
Arguments:
export_folder(str): The path to export to. By default will use the global export folder
file_prefix (str): Exported file name prefix
capitalize_file_names(bool): Make all file names upper case
Returns:
A list of files exported
"""
res = self._execute_command(exportWellLogPlotData=Commands_pb2.ExportWellLogPlotDataRequest(exportFormat='ASCII',
viewId=self.id,
exportFolder=export_folder,
filePrefix=file_prefix,
exportTvdRkb=False,
capitalizeFileNames=capitalize_file_names,
resampleInterval=0.0))
return res.exportWellLogPlotDataResult.exportedFiles

View File

@@ -0,0 +1,23 @@
from setuptools import setup, find_packages
with open('README.md') as f:
readme = f.read()
with open('LICENSE') as f:
license = f.read()
RIPS_DIST_VERSION = '1'
setup(
name='rips',
version='@RESINSIGHT_MAJOR_VERSION@.@RESINSIGHT_MINOR_VERSION@.@RESINSIGHT_PATCH_VERSION@.' + RIPS_DIST_VERSION,
description='Python Interface for ResInsight',
long_description=readme,
author='Ceetron Solutions',
author_email='info@ceetronsolutions.com',
url='http://www.resinsight.org',
license=license,
packages=['rips'],
package_data={'rips': ['*.py', 'generated/*.py', 'PythonExamples/*.py', 'tests/*.py']},
install_requires=['grpcio>=1.20.0']
)

View File

@@ -0,0 +1,75 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#include "RiaGrpcAppService.h"
#include "RiaGrpcCallbacks.h"
#include "RiaGrpcServer.h"
#include "RiaGuiApplication.h"
#include "RiaVersionInfo.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcAppService::GetVersion( grpc::ServerContext* context, const rips::Empty* request, rips::Version* reply )
{
reply->set_major_version( QString( RESINSIGHT_MAJOR_VERSION ).toInt() );
reply->set_minor_version( QString( RESINSIGHT_MINOR_VERSION ).toInt() );
reply->set_patch_version( QString( RESINSIGHT_PATCH_VERSION ).toInt() );
return grpc::Status::OK;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcAppService::Exit( grpc::ServerContext* context, const rips::Empty* request, rips::Empty* reply )
{
RiaGrpcServer::setReceivedExitRequest();
return grpc::Status::OK;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status
RiaGrpcAppService::GetRuntimeInfo( grpc::ServerContext* context, const rips::Empty* request, rips::RuntimeInfo* reply )
{
rips::ApplicationTypeEnum appType = rips::CONSOLE_APPLICATION;
if ( RiaGuiApplication::isRunning() )
{
appType = rips::GUI_APPLICATION;
}
reply->set_app_type( appType );
return grpc::Status::OK;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RiaGrpcCallbackInterface*> RiaGrpcAppService::createCallbacks()
{
typedef RiaGrpcAppService Self;
return { new RiaGrpcUnaryCallback<Self, rips::Empty, rips::Version>( this, &Self::GetVersion, &Self::RequestGetVersion ),
new RiaGrpcUnaryCallback<Self, rips::Empty, rips::Empty>( this, &Self::Exit, &Self::RequestExit ),
new RiaGrpcUnaryCallback<Self, rips::Empty, rips::RuntimeInfo>( this,
&Self::GetRuntimeInfo,
&Self::RequestGetRuntimeInfo ) };
}
static bool RiaGrpcAppInfoService_init =
RiaGrpcServiceFactory::instance()->registerCreator<RiaGrpcAppService>( typeid( RiaGrpcAppService ).hash_code() );

View File

@@ -0,0 +1,49 @@
#pragma once
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RiaGrpcServiceInterface.h"
#include "App.grpc.pb.h"
#include <grpcpp/grpcpp.h>
#include <vector>
namespace rips
{
class Empty;
class Version;
} // namespace rips
namespace caf
{
class PdmValueField;
}
class RiaGrpcCallbackInterface;
class RiaGrpcAppService : public rips::App::AsyncService, public RiaGrpcServiceInterface
{
public:
grpc::Status GetVersion( grpc::ServerContext* context, const rips::Empty* request, rips::Version* reply ) override;
grpc::Status Exit( grpc::ServerContext* context, const rips::Empty* request, rips::Empty* reply ) override;
grpc::Status GetRuntimeInfo( grpc::ServerContext* context, const rips::Empty* request, rips::RuntimeInfo* reply ) override;
std::vector<RiaGrpcCallbackInterface*> createCallbacks() override;
};

View File

@@ -0,0 +1,217 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RiaLogging.h"
#include <QString>
#include <grpc/support/log.h>
#include <grpcpp/grpcpp.h>
#include <grpcpp/server_context.h>
#include <grpcpp/support/async_stream.h>
#include <grpcpp/support/async_unary_call.h>
#include <grpcpp/support/sync_stream.h>
using grpc::CompletionQueue;
using grpc::ServerAsyncReader;
using grpc::ServerAsyncResponseWriter;
using grpc::ServerAsyncWriter;
using grpc::ServerCompletionQueue;
using grpc::ServerContext;
using grpc::Status;
class RiaGrpcServiceInterface;
//==================================================================================================
//
// Base class for all gRPC-callbacks
//
//==================================================================================================
class RiaGrpcCallbackInterface
{
public:
enum CallState
{
CREATE_HANDLER,
INIT_REQUEST_STARTED,
INIT_REQUEST_COMPLETED,
PROCESS_REQUEST,
FINISH_REQUEST
};
public:
inline RiaGrpcCallbackInterface();
virtual ~RiaGrpcCallbackInterface() {}
virtual QString name() const = 0;
virtual RiaGrpcCallbackInterface* createNewFromThis() const = 0;
virtual void createRequestHandler( ServerCompletionQueue* completionQueue ) = 0;
virtual void onInitRequestStarted() {}
virtual void onInitRequestCompleted() {}
virtual void onProcessRequest() = 0;
virtual void onFinishRequest() {}
inline CallState callState() const;
inline const Status& status() const;
inline void setNextCallState( CallState state );
protected:
CallState m_state;
Status m_status;
};
//==================================================================================================
//
// Templated gRPC-callback base class
//
//==================================================================================================
template <typename ServiceT, typename RequestT, typename ReplyT>
class RiaGrpcServiceCallback : public RiaGrpcCallbackInterface
{
public:
RiaGrpcServiceCallback( ServiceT* service );
QString name() const override;
const RequestT& request() const;
ReplyT& reply();
protected:
virtual QString methodType() const = 0;
protected:
ServiceT* m_service;
RequestT m_request;
ReplyT m_reply;
};
//==================================================================================================
//
// Templated gRPC-callback for non-streaming services
//
//==================================================================================================
template <typename ServiceT, typename RequestT, typename ReplyT>
class RiaGrpcUnaryCallback : public RiaGrpcServiceCallback<ServiceT, RequestT, ReplyT>
{
public:
using ResponseWriterT = ServerAsyncResponseWriter<ReplyT>;
using MethodImplT = std::function<Status( ServiceT&, ServerContext*, const RequestT*, ReplyT* )>;
using MethodRequestT = std::function<
void( ServiceT&, ServerContext*, RequestT*, ResponseWriterT*, CompletionQueue*, ServerCompletionQueue*, void* )>;
RiaGrpcUnaryCallback( ServiceT* service, MethodImplT methodImpl, MethodRequestT methodRequest );
RiaGrpcCallbackInterface* createNewFromThis() const override;
void createRequestHandler( ServerCompletionQueue* completionQueue ) override;
void onProcessRequest() override;
protected:
virtual QString methodType() const override;
private:
ServerContext m_context;
ResponseWriterT m_responder;
MethodImplT m_methodImpl;
MethodRequestT m_methodRequest;
};
//==================================================================================================
//
// Templated server->client *streaming* gRPC-callback calling service implementation callbacks
//
// The streaming callback needs a state handler for setting up and maintaining order.
//
// A fully functional state handler for server->client streaming needs to implement the following methods:
// 1. Default Constructor
// 2. grpc::Status init(const grpc::Message* request)
//
//==================================================================================================
template <typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
class RiaGrpcServerToClientStreamCallback : public RiaGrpcServiceCallback<ServiceT, RequestT, ReplyT>
{
public:
using ResponseWriterT = ServerAsyncWriter<ReplyT>;
using MethodImplT = std::function<Status( ServiceT&, ServerContext*, const RequestT*, ReplyT*, StateHandlerT* )>;
using MethodRequestT = std::function<
void( ServiceT&, ServerContext*, RequestT*, ResponseWriterT*, CompletionQueue*, ServerCompletionQueue*, void* )>;
RiaGrpcServerToClientStreamCallback( ServiceT* service,
MethodImplT methodImpl,
MethodRequestT methodRequest,
StateHandlerT* stateHandler );
RiaGrpcCallbackInterface* createNewFromThis() const override;
void createRequestHandler( ServerCompletionQueue* completionQueue ) override;
void onInitRequestCompleted() override;
void onProcessRequest() override;
protected:
virtual QString methodType() const override;
private:
ServerContext m_context;
ResponseWriterT m_responder;
MethodImplT m_methodImpl;
MethodRequestT m_methodRequest;
std::unique_ptr<StateHandlerT> m_stateHandler;
};
//==================================================================================================
//
// Templated client->server *streaming* gRPC-callback calling service implementation callbacks
//
// The streaming callback needs a state handler for setting up and maintaining order.
//
// A fully functional state handler for client->server streaming needs to implement the following methods:
// 1. Default Constructor
// 2. grpc::Status init(const grpc::Message* request)
// 3. void finish() any updates required after completion
//
//==================================================================================================
template <typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
class RiaGrpcClientToServerStreamCallback : public RiaGrpcServiceCallback<ServiceT, RequestT, ReplyT>
{
public:
using RequestReaderT = ServerAsyncReader<ReplyT, RequestT>;
using MethodImplT = std::function<Status( ServiceT&, ServerContext*, const RequestT*, ReplyT*, StateHandlerT* )>;
using MethodRequestT =
std::function<void( ServiceT&, ServerContext*, RequestReaderT*, CompletionQueue*, ServerCompletionQueue*, void* )>;
RiaGrpcClientToServerStreamCallback( ServiceT* service,
MethodImplT methodImpl,
MethodRequestT methodRequest,
StateHandlerT* stateHandler );
RiaGrpcCallbackInterface* createNewFromThis() const override;
void createRequestHandler( ServerCompletionQueue* completionQueue ) override;
void onInitRequestStarted() override;
void onInitRequestCompleted() override;
void onProcessRequest() override;
void onFinishRequest() override;
protected:
virtual QString methodType() const override;
private:
ServerContext m_context;
RequestReaderT m_reader;
MethodImplT m_methodImpl;
MethodRequestT m_methodRequest;
std::unique_ptr<StateHandlerT> m_stateHandler;
};
#include "RiaGrpcCallbacks.inl"

View File

@@ -0,0 +1,380 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
inline RiaGrpcCallbackInterface::RiaGrpcCallbackInterface()
: m_state( CREATE_HANDLER )
, m_status( Status::OK )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaGrpcCallbackInterface::CallState RiaGrpcCallbackInterface::callState() const
{
return m_state;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const Status& RiaGrpcCallbackInterface::status() const
{
return m_status;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
inline void RiaGrpcCallbackInterface::setNextCallState( CallState state )
{
m_state = state;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT>
RiaGrpcServiceCallback<ServiceT, RequestT, ReplyT>::RiaGrpcServiceCallback( ServiceT* service )
: m_service( service )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT>
QString RiaGrpcServiceCallback<ServiceT, RequestT, ReplyT>::name() const
{
QString fullName = QString( "%1:%2(%3, %4)" )
.arg( typeid( ServiceT ).name() )
.arg( methodType() )
.arg( typeid( RequestT ).name() )
.arg( typeid( ReplyT ).name() );
return fullName;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT>
const RequestT& RiaGrpcServiceCallback<ServiceT, RequestT, ReplyT>::request() const
{
return m_request;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT>
ReplyT& RiaGrpcServiceCallback<ServiceT, RequestT, ReplyT>::reply()
{
return m_reply;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT>
RiaGrpcUnaryCallback<ServiceT, RequestT, ReplyT>::RiaGrpcUnaryCallback( ServiceT* service,
MethodImplT methodImpl,
MethodRequestT methodRequest )
: RiaGrpcServiceCallback<ServiceT, RequestT, ReplyT>( service )
, m_responder( &m_context )
, m_methodImpl( methodImpl )
, m_methodRequest( methodRequest )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT>
RiaGrpcCallbackInterface* RiaGrpcUnaryCallback<ServiceT, RequestT, ReplyT>::createNewFromThis() const
{
return new RiaGrpcUnaryCallback<ServiceT, RequestT, ReplyT>( this->m_service, this->m_methodImpl, this->m_methodRequest );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT>
void RiaGrpcUnaryCallback<ServiceT, RequestT, ReplyT>::createRequestHandler( ServerCompletionQueue* completionQueue )
{
// The Request-method is where the service gets registered to respond to a given request.
m_methodRequest( *this->m_service, &m_context, &this->m_request, &m_responder, completionQueue, completionQueue, this );
// Simple unary requests don't need initialisation, so proceed to process as soon as a request turns up.
this->setNextCallState( RiaGrpcCallbackInterface::PROCESS_REQUEST );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT>
void RiaGrpcUnaryCallback<ServiceT, RequestT, ReplyT>::onProcessRequest()
{
// Call request handler method
this->m_status = m_methodImpl( *this->m_service, &m_context, &this->m_request, &this->m_reply );
// Simply unary requests are finished as soon as you've done any processing.
// So next time we receive a new tag on the command queue we should proceed to finish.
this->setNextCallState( RiaGrpcCallbackInterface::FINISH_REQUEST );
// Finish will push this callback back on the command queue (now with Finish as the call state).
m_responder.Finish( this->m_reply, this->m_status, this );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT>
QString RiaGrpcUnaryCallback<ServiceT, RequestT, ReplyT>::methodType() const
{
return "RegularMethod";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
RiaGrpcServerToClientStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::RiaGrpcServerToClientStreamCallback(
ServiceT* service,
MethodImplT methodImpl,
MethodRequestT methodRequest,
StateHandlerT* stateHandler )
: RiaGrpcServiceCallback<ServiceT, RequestT, ReplyT>( service )
, m_responder( &m_context )
, m_methodImpl( methodImpl )
, m_methodRequest( methodRequest )
, m_stateHandler( stateHandler )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
RiaGrpcCallbackInterface*
RiaGrpcServerToClientStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::createNewFromThis() const
{
return new RiaGrpcServerToClientStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>( this->m_service,
m_methodImpl,
m_methodRequest,
new StateHandlerT );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
void RiaGrpcServerToClientStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::createRequestHandler(
ServerCompletionQueue* completionQueue )
{
// The Request-method is where the service gets registered to respond to a given request.
m_methodRequest( *this->m_service, &m_context, &this->m_request, &m_responder, completionQueue, completionQueue, this );
// Server->Client Streaming requests require initialisation. However, we receive the complete request immediately.
// So can proceed directly to completion of the init request.
this->setNextCallState( RiaGrpcCallbackInterface::INIT_REQUEST_COMPLETED );
}
//--------------------------------------------------------------------------------------------------
/// Perform initialisation tasks at the time of receiving a complete request
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
void RiaGrpcServerToClientStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::onInitRequestCompleted()
{
// Initialise streaming state handler
this->m_status = m_stateHandler->init( &this->m_request );
if ( !this->m_status.ok() )
{
// We have an error. Proceed to finish and report the status
this->setNextCallState( RiaGrpcCallbackInterface::FINISH_REQUEST );
m_responder.Finish( this->m_status, this );
return;
}
// Move on to processing and perform the first processing immediately since the client will
// not request anything more.
this->setNextCallState( RiaGrpcCallbackInterface::PROCESS_REQUEST );
this->onProcessRequest();
}
//--------------------------------------------------------------------------------------------------
/// Process a streaming request and send one package
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
void RiaGrpcServerToClientStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::onProcessRequest()
{
this->m_reply = ReplyT(); // Make sure it is reset
// Call request handler method
this->m_status = m_methodImpl( *this->m_service, &m_context, &this->m_request, &this->m_reply, m_stateHandler.get() );
if ( this->m_status.ok() )
{
// The write call will send data to client AND put this callback back on the command queue
// so that this method gets called again to send the next stream package.
m_responder.Write( this->m_reply, this );
}
else
{
this->setNextCallState( RiaGrpcCallbackInterface::FINISH_REQUEST );
// Out of range means we're finished but it isn't an error
if ( this->m_status.error_code() == grpc::OUT_OF_RANGE )
{
this->m_status = Status::OK;
}
// Finish will put this callback back on the command queue, now with a finish state.
m_responder.Finish( this->m_status, this );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
QString RiaGrpcServerToClientStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::methodType() const
{
return "StreamingMethod";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
RiaGrpcClientToServerStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::RiaGrpcClientToServerStreamCallback(
ServiceT* service,
MethodImplT methodImpl,
MethodRequestT methodRequest,
StateHandlerT* stateHandler )
: RiaGrpcServiceCallback<ServiceT, RequestT, ReplyT>( service )
, m_reader( &m_context )
, m_methodImpl( methodImpl )
, m_methodRequest( methodRequest )
, m_stateHandler( stateHandler )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
RiaGrpcCallbackInterface*
RiaGrpcClientToServerStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::createNewFromThis() const
{
return new RiaGrpcClientToServerStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>( this->m_service,
m_methodImpl,
m_methodRequest,
new StateHandlerT( true ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
void RiaGrpcClientToServerStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::createRequestHandler(
ServerCompletionQueue* completionQueue )
{
// The Request-method is where the service gets registered to respond to a given request.
m_methodRequest( *this->m_service, &m_context, &this->m_reader, completionQueue, completionQueue, this );
// The client->server streaming requires initialisation and each request package is streamed asynchronously
// So we need to start and complete the init request.
this->setNextCallState( RiaGrpcCallbackInterface::INIT_REQUEST_STARTED );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
void RiaGrpcClientToServerStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::onInitRequestStarted()
{
this->setNextCallState( RiaGrpcCallbackInterface::INIT_REQUEST_COMPLETED );
// The read call will start reading the request data and push this callback back onto the command queue
// when the read call is completed.
m_reader.Read( &this->m_request, this );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
void RiaGrpcClientToServerStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::onInitRequestCompleted()
{
this->setNextCallState( RiaGrpcCallbackInterface::PROCESS_REQUEST );
// Fully received the stream package so can now init
this->m_status = m_stateHandler->init( &this->m_request );
if ( !this->m_status.ok() )
{
// We have an error. Proceed to finish and report the status
m_reader.FinishWithError( this->m_status, this );
this->setNextCallState( RiaGrpcCallbackInterface::FINISH_REQUEST );
return;
}
// Start reading and push this back onto the command queue.
m_reader.Read( &this->m_request, this );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
void RiaGrpcClientToServerStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::onProcessRequest()
{
this->m_reply = ReplyT(); // Make sure it is reset
// Call request handler method
this->m_status = m_methodImpl( *this->m_service, &m_context, &this->m_request, &this->m_reply, m_stateHandler.get() );
if ( !this->m_status.ok() )
{
this->setNextCallState( RiaGrpcCallbackInterface::FINISH_REQUEST );
m_reader.FinishWithError( this->m_status, this );
}
else
{
CAF_ASSERT( m_stateHandler->streamedValueCount() <= m_stateHandler->totalValueCount() );
if ( m_stateHandler->streamedValueCount() == m_stateHandler->totalValueCount() )
{
this->setNextCallState( RiaGrpcCallbackInterface::FINISH_REQUEST );
m_reader.Finish( this->m_reply, grpc::Status::OK, this );
}
else
{
m_reader.Read( &this->m_request, this );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
void RiaGrpcClientToServerStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::onFinishRequest()
{
m_stateHandler->finish();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename ServiceT, typename RequestT, typename ReplyT, typename StateHandlerT>
QString RiaGrpcClientToServerStreamCallback<ServiceT, RequestT, ReplyT, StateHandlerT>::methodType() const
{
return "ClientStreamingMethod";
}

View File

@@ -0,0 +1,778 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#include "RiaGrpcCaseService.h"
#include "RiaGrpcCallbacks.h"
#include "RiaGrpcHelper.h"
#include "RiaSocketTools.h"
#include "RigActiveCellInfo.h"
#include "RigCaseCellResultsData.h"
#include "RigEclipseCaseData.h"
#include "RigEclipseResultAddress.h"
#include "RigMainGrid.h"
#include "RimEclipseCase.h"
#include "RimEclipseResultDefinition.h"
#include "Riu3dSelectionManager.h"
using namespace rips;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaActiveCellInfoStateHandler::RiaActiveCellInfoStateHandler()
: m_request( nullptr )
, m_eclipseCase( nullptr )
, m_activeCellInfo( nullptr )
, m_currentCellIdx( 0u )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaActiveCellInfoStateHandler::init( const rips::CellInfoRequest* request )
{
CAF_ASSERT( request );
m_request = request;
m_porosityModel = RiaDefines::PorosityModelType( m_request->porosity_model() );
RimCase* rimCase = RiaGrpcServiceInterface::findCase( m_request->case_request().id() );
m_eclipseCase = dynamic_cast<RimEclipseCase*>( rimCase );
if ( !m_eclipseCase )
{
return grpc::Status( grpc::NOT_FOUND, "Eclipse Case not found" );
}
if ( !m_eclipseCase->eclipseCaseData() || !m_eclipseCase->eclipseCaseData()->mainGrid() )
{
return grpc::Status( grpc::NOT_FOUND, "Eclipse Case Data not found" );
}
m_activeCellInfo = m_eclipseCase->eclipseCaseData()->activeCellInfo( m_porosityModel );
if ( !m_activeCellInfo )
{
return grpc::Status( grpc::NOT_FOUND, "Active Cell Info not found" );
}
size_t globalCoarseningBoxCount = 0;
for ( size_t gridIdx = 0; gridIdx < m_eclipseCase->eclipseCaseData()->gridCount(); gridIdx++ )
{
m_globalCoarseningBoxIndexStart.push_back( globalCoarseningBoxCount );
RigGridBase* grid = m_eclipseCase->eclipseCaseData()->grid( gridIdx );
size_t localCoarseningBoxCount = grid->coarseningBoxCount();
globalCoarseningBoxCount += localCoarseningBoxCount;
}
return grpc::Status::OK;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaActiveCellInfoStateHandler::assignNextActiveCellInfoData( rips::CellInfo* cellInfo )
{
const std::vector<RigCell>& reservoirCells = m_eclipseCase->eclipseCaseData()->mainGrid()->globalCellArray();
while ( m_currentCellIdx < reservoirCells.size() )
{
size_t cellIdxToTry = m_currentCellIdx++;
if ( m_activeCellInfo->isActive( cellIdxToTry ) )
{
assignCellInfoData( cellInfo, reservoirCells, cellIdxToTry );
return grpc::Status::OK;
}
}
return Status( grpc::OUT_OF_RANGE, "We've reached the end. This is not an error but means transmission is finished" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaActiveCellInfoStateHandler::assignCellInfoData( rips::CellInfo* cellInfo,
const std::vector<RigCell>& reservoirCells,
size_t cellIdx )
{
RigGridBase* grid = reservoirCells[cellIdx].hostGrid();
CVF_ASSERT( grid != nullptr );
size_t cellIndex = reservoirCells[cellIdx].gridLocalCellIndex();
size_t i, j, k;
grid->ijkFromCellIndex( cellIndex, &i, &j, &k );
size_t pi, pj, pk;
RigGridBase* parentGrid = nullptr;
if ( grid->isMainGrid() )
{
pi = i;
pj = j;
pk = k;
parentGrid = grid;
}
else
{
size_t parentCellIdx = reservoirCells[cellIdx].parentCellIndex();
parentGrid = ( static_cast<RigLocalGrid*>( grid ) )->parentGrid();
CVF_ASSERT( parentGrid != nullptr );
parentGrid->ijkFromCellIndex( parentCellIdx, &pi, &pj, &pk );
}
cellInfo->set_grid_index( (int)grid->gridIndex() );
cellInfo->set_parent_grid_index( (int)parentGrid->gridIndex() );
size_t coarseningIdx = reservoirCells[cellIdx].coarseningBoxIndex();
if ( coarseningIdx != cvf::UNDEFINED_SIZE_T )
{
size_t globalCoarseningIdx = m_globalCoarseningBoxIndexStart[grid->gridIndex()] + coarseningIdx;
cellInfo->set_coarsening_box_index( (int)globalCoarseningIdx );
}
else
{
cellInfo->set_coarsening_box_index( -1 );
}
{
rips::Vec3i* local_ijk = new rips::Vec3i;
local_ijk->set_i( (int)i );
local_ijk->set_j( (int)j );
local_ijk->set_k( (int)k );
cellInfo->set_allocated_local_ijk( local_ijk );
}
{
rips::Vec3i* parent_ijk = new rips::Vec3i;
parent_ijk->set_i( (int)pi );
parent_ijk->set_j( (int)pj );
parent_ijk->set_k( (int)pk );
cellInfo->set_allocated_parent_ijk( parent_ijk );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigActiveCellInfo* RiaActiveCellInfoStateHandler::activeCellInfo() const
{
return m_activeCellInfo;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<RigCell>& RiaActiveCellInfoStateHandler::reservoirCells() const
{
const std::vector<RigCell>& reservoirCells = m_eclipseCase->eclipseCaseData()->mainGrid()->globalCellArray();
return reservoirCells;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaActiveCellInfoStateHandler::assignReply( rips::CellInfoArray* reply )
{
const size_t packageSize = RiaGrpcServiceInterface::numberOfDataUnitsInPackage( sizeof( rips::CellInfo ) );
size_t indexInPackage = 0u;
reply->mutable_data()->Reserve( (int)packageSize );
// Stream until you've reached the package size or total cell count. Whatever comes first.
// If you've reached the package size you'll come back for another round.
for ( ; indexInPackage < packageSize && m_currentCellIdx < m_activeCellInfo->reservoirCellCount(); ++indexInPackage )
{
rips::CellInfo singleCellInfo;
grpc::Status singleCellInfoStatus = assignNextActiveCellInfoData( &singleCellInfo );
if ( singleCellInfoStatus.ok() )
{
rips::CellInfo* allocCellInfo = reply->add_data();
*allocCellInfo = singleCellInfo;
}
else
{
break;
}
}
if ( indexInPackage > 0u )
{
return Status::OK;
}
return Status( grpc::OUT_OF_RANGE, "We've reached the end. This is not an error but means transmission is finished" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaActiveCellInfoStateHandler::assignNextActiveCellCenter( rips::Vec3d* cellCenter )
{
const std::vector<RigCell>& reservoirCells = m_eclipseCase->eclipseCaseData()->mainGrid()->globalCellArray();
while ( m_currentCellIdx < reservoirCells.size() )
{
size_t cellIdxToTry = m_currentCellIdx++;
if ( m_activeCellInfo->isActive( cellIdxToTry ) )
{
assignCellCenter( cellCenter, reservoirCells, cellIdxToTry );
return grpc::Status::OK;
}
}
return Status( grpc::OUT_OF_RANGE, "We've reached the end. This is not an error but means transmission is finished" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaActiveCellInfoStateHandler::assignCellCenter( rips::Vec3d* cellCenter,
const std::vector<RigCell>& reservoirCells,
size_t cellIdx )
{
cvf::Vec3d center = reservoirCells[cellIdx].center();
RiaGrpcHelper::convertVec3dToPositiveDepth( &center );
cellCenter->set_x( center.x() );
cellCenter->set_y( center.y() );
cellCenter->set_z( center.z() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaActiveCellInfoStateHandler::assignCellCentersReply( rips::CellCenters* reply )
{
const size_t packageSize = RiaGrpcServiceInterface::numberOfDataUnitsInPackage( sizeof( rips::Vec3d ) );
size_t indexInPackage = 0u;
reply->mutable_centers()->Reserve( (int)packageSize );
for ( ; indexInPackage < packageSize && m_currentCellIdx < m_activeCellInfo->reservoirCellCount(); ++indexInPackage )
{
rips::Vec3d singleCellCenter;
grpc::Status singleCellCenterStatus = assignNextActiveCellCenter( &singleCellCenter );
if ( singleCellCenterStatus.ok() )
{
rips::Vec3d* allocCellCenter = reply->add_centers();
*allocCellCenter = singleCellCenter;
}
else
{
break;
}
}
if ( indexInPackage > 0u )
{
return Status::OK;
}
return Status( grpc::OUT_OF_RANGE, "We've reached the end. This is not an error but means transmission is finished" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Status RiaActiveCellInfoStateHandler::assignNextActiveCellCorners( rips::CellCorners* cellCorners )
{
const std::vector<RigCell>& reservoirCells = m_eclipseCase->eclipseCaseData()->mainGrid()->globalCellArray();
while ( m_currentCellIdx < reservoirCells.size() )
{
size_t cellIdxToTry = m_currentCellIdx++;
if ( m_activeCellInfo->isActive( cellIdxToTry ) )
{
assignCellCorners( cellCorners, reservoirCells, cellIdxToTry );
return grpc::Status::OK;
}
}
return Status( grpc::OUT_OF_RANGE, "We've reached the end. This is not an error but means transmission is finished" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaActiveCellInfoStateHandler::assignCellCorners( rips::CellCorners* corners,
const std::vector<RigCell>& reservoirCells,
size_t cellIdx )
{
cvf::Vec3d cornerVerts[8];
RigGridBase* grid = m_eclipseCase->eclipseCaseData()->mainGrid();
grid->cellCornerVertices( cellIdx, cornerVerts );
for ( cvf::Vec3d& corner : cornerVerts )
{
RiaGrpcHelper::convertVec3dToPositiveDepth( &corner );
}
RiaGrpcHelper::setCornerValues( corners->mutable_c0(), cornerVerts[0] );
RiaGrpcHelper::setCornerValues( corners->mutable_c1(), cornerVerts[1] );
RiaGrpcHelper::setCornerValues( corners->mutable_c2(), cornerVerts[2] );
RiaGrpcHelper::setCornerValues( corners->mutable_c3(), cornerVerts[3] );
RiaGrpcHelper::setCornerValues( corners->mutable_c4(), cornerVerts[4] );
RiaGrpcHelper::setCornerValues( corners->mutable_c5(), cornerVerts[5] );
RiaGrpcHelper::setCornerValues( corners->mutable_c6(), cornerVerts[6] );
RiaGrpcHelper::setCornerValues( corners->mutable_c7(), cornerVerts[7] );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Status RiaActiveCellInfoStateHandler::assignCellCornersReply( rips::CellCornersArray* reply )
{
const size_t packageSize = RiaGrpcServiceInterface::numberOfDataUnitsInPackage( sizeof( rips::CellCorners ) );
size_t indexInPackage = 0u;
reply->mutable_cells()->Reserve( (int)packageSize );
for ( ; indexInPackage < packageSize && m_currentCellIdx < m_activeCellInfo->reservoirCellCount(); ++indexInPackage )
{
rips::CellCorners singleCellCorners;
grpc::Status singleCellCornersStatus = assignNextActiveCellCorners( &singleCellCorners );
if ( singleCellCornersStatus.ok() )
{
rips::CellCorners* allocCellCorners = reply->add_cells();
*allocCellCorners = singleCellCorners;
}
else
{
break;
}
}
if ( indexInPackage > 0u )
{
return Status::OK;
}
return Status( grpc::OUT_OF_RANGE, "We've reached the end. This is not an error but means transmission is finished" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcCaseService::GetGridCount( grpc::ServerContext* context,
const rips::CaseRequest* request,
rips::GridCount* reply )
{
RimCase* rimCase = findCase( request->id() );
RimEclipseCase* eclipseCase = dynamic_cast<RimEclipseCase*>( rimCase );
if ( eclipseCase )
{
int gridCount = (int)eclipseCase->mainGrid()->gridCount();
reply->set_count( gridCount );
return Status::OK;
}
return grpc::Status( grpc::NOT_FOUND, "Eclipse Case not found" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcCaseService::GetCellCount( grpc::ServerContext* context,
const rips::CellInfoRequest* request,
rips::CellCount* reply )
{
RimCase* rimCase = findCase( request->case_request().id() );
RimEclipseCase* eclipseCase = dynamic_cast<RimEclipseCase*>( rimCase );
if ( eclipseCase )
{
auto porosityModel = RiaDefines::PorosityModelType( request->porosity_model() );
RigActiveCellInfo* activeCellInfo = eclipseCase->eclipseCaseData()->activeCellInfo( porosityModel );
reply->set_active_cell_count( (int)activeCellInfo->reservoirActiveCellCount() );
reply->set_reservoir_cell_count( (int)activeCellInfo->reservoirCellCount() );
return grpc::Status::OK;
}
return grpc::Status( grpc::NOT_FOUND, "Eclipse Case not found" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcCaseService::GetTimeSteps( grpc::ServerContext* context,
const rips::CaseRequest* request,
rips::TimeStepDates* reply )
{
RimCase* rimCase = findCase( request->id() );
if ( rimCase )
{
std::vector<QDateTime> timeStepDates = rimCase->timeStepDates();
for ( QDateTime dateTime : timeStepDates )
{
rips::TimeStepDate* date = reply->add_dates();
date->set_year( dateTime.date().year() );
date->set_month( dateTime.date().month() );
date->set_day( dateTime.date().day() );
date->set_hour( dateTime.time().hour() );
date->set_minute( dateTime.time().minute() );
date->set_second( dateTime.time().second() );
}
return grpc::Status::OK;
}
return grpc::Status( grpc::NOT_FOUND, "Case not found" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcCaseService::GetDaysSinceStart( grpc::ServerContext* context,
const rips::CaseRequest* request,
rips::DaysSinceStart* reply )
{
RimCase* rimCase = findCase( request->id() );
RimEclipseCase* eclipseCase = dynamic_cast<RimEclipseCase*>( rimCase );
if ( eclipseCase )
{
RigEclipseResultAddress addrToMaxTimeStepCountResult;
if ( eclipseCase && eclipseCase->eclipseCaseData() )
{
eclipseCase->eclipseCaseData()
->results( RiaDefines::PorosityModelType::MATRIX_MODEL )
->maxTimeStepCount( &addrToMaxTimeStepCountResult );
if ( !addrToMaxTimeStepCountResult.isValid() )
{
return grpc::Status( grpc::NOT_FOUND, "Invalid result. No time steps found." );
}
}
std::vector<double> daysSinceSimulationStart = eclipseCase->eclipseCaseData()
->results( RiaDefines::PorosityModelType::MATRIX_MODEL )
->daysSinceSimulationStart( addrToMaxTimeStepCountResult );
for ( auto days : daysSinceSimulationStart )
{
reply->add_day_decimals( days );
}
return grpc::Status::OK;
}
return grpc::Status( grpc::NOT_FOUND, "Eclipse Case not found" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status
RiaGrpcCaseService::GetCaseInfo( grpc::ServerContext* context, const rips::CaseRequest* request, rips::CaseInfo* reply )
{
RimCase* rimCase = findCase( request->id() );
if ( rimCase )
{
qint64 caseId = rimCase->caseId();
qint64 caseGroupId = -1;
QString caseName, caseType;
RiaSocketTools::getCaseInfoFromCase( rimCase, caseId, caseName, caseType, caseGroupId );
reply->set_id( caseId );
reply->set_group_id( caseGroupId );
reply->set_name( caseName.toStdString() );
reply->set_type( caseType.toStdString() );
return Status::OK;
}
return Status( grpc::NOT_FOUND, "Case not found" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcCaseService::GetPdmObject( grpc::ServerContext* context,
const rips::CaseRequest* request,
rips::PdmObject* reply )
{
RimCase* rimCase = findCase( request->id() );
if ( rimCase )
{
copyPdmObjectFromCafToRips( rimCase, reply );
}
return grpc::Status::OK;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcCaseService::GetCellInfoForActiveCells( grpc::ServerContext* context,
const rips::CellInfoRequest* request,
rips::CellInfoArray* reply,
RiaActiveCellInfoStateHandler* stateHandler )
{
return stateHandler->assignReply( reply );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcCaseService::GetCellCenterForActiveCells( grpc::ServerContext* context,
const rips::CellInfoRequest* request,
rips::CellCenters* reply,
RiaActiveCellInfoStateHandler* stateHandler )
{
return stateHandler->assignCellCentersReply( reply );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcCaseService::GetCellCornersForActiveCells( grpc::ServerContext* context,
const rips::CellInfoRequest* request,
rips::CellCornersArray* reply,
RiaActiveCellInfoStateHandler* stateHandler )
{
return stateHandler->assignCellCornersReply( reply );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaSelectedCellsStateHandler::RiaSelectedCellsStateHandler()
: m_request( nullptr )
, m_eclipseCase( nullptr )
, m_currentItem( 0u )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Status RiaSelectedCellsStateHandler::init( const rips::CaseRequest* request )
{
CAF_ASSERT( request );
m_request = request;
RimCase* rimCase = RiaGrpcServiceInterface::findCase( m_request->id() );
m_eclipseCase = dynamic_cast<RimEclipseCase*>( rimCase );
if ( !m_eclipseCase )
{
return grpc::Status( grpc::NOT_FOUND, "Eclipse Case not found" );
}
if ( !m_eclipseCase->eclipseCaseData() || !m_eclipseCase->eclipseCaseData()->mainGrid() )
{
return grpc::Status( grpc::NOT_FOUND, "Eclipse Case Data not found" );
}
return grpc::Status::OK;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
Status RiaSelectedCellsStateHandler::assignNextSelectedCell( rips::SelectedCell* cell,
const std::vector<RiuEclipseSelectionItem*>& items )
{
while ( m_currentItem < items.size() )
{
size_t itemToTry = m_currentItem++;
const RiuEclipseSelectionItem* item = items[itemToTry];
CVF_ASSERT( item->type() == RiuSelectionItem::ECLIPSE_SELECTION_OBJECT );
assignSelectedCell( cell, item );
return grpc::Status::OK;
}
return Status( grpc::OUT_OF_RANGE, "We've reached the end. This is not an error but means transmission is finished" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaSelectedCellsStateHandler::assignSelectedCell( rips::SelectedCell* cell, const RiuEclipseSelectionItem* item )
{
CVF_ASSERT( item->type() == RiuSelectionItem::ECLIPSE_SELECTION_OBJECT );
size_t i = -1;
size_t j = -1;
size_t k = -1;
item->m_resultDefinition->eclipseCase()
->eclipseCaseData()
->grid( item->m_gridIndex )
->ijkFromCellIndex( item->m_gridLocalCellIndex, &i, &j, &k );
cell->set_grid_index( item->m_gridIndex );
rips::Vec3i* ijk = new rips::Vec3i;
ijk->set_i( (int)i );
ijk->set_j( (int)j );
ijk->set_k( (int)k );
cell->set_allocated_ijk( ijk );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaSelectedCellsStateHandler::assignReply( rips::SelectedCells* reply )
{
std::vector<RiuSelectionItem*> items;
Riu3dSelectionManager::instance()->selectedItems( items );
// Only eclipse cases are currently supported. Also filter by case.
std::vector<RiuEclipseSelectionItem*> eclipseItems;
for ( auto item : items )
{
RiuEclipseSelectionItem* eclipseItem = dynamic_cast<RiuEclipseSelectionItem*>( item );
if ( eclipseItem && eclipseItem->m_resultDefinition->eclipseCase()->caseId == m_request->id() )
{
eclipseItems.push_back( eclipseItem );
}
}
const size_t packageSize = RiaGrpcServiceInterface::numberOfDataUnitsInPackage( sizeof( rips::SelectedCell ) );
size_t indexInPackage = 0u;
reply->mutable_cells()->Reserve( (int)packageSize );
for ( ; indexInPackage < packageSize && m_currentItem < eclipseItems.size(); ++indexInPackage )
{
rips::SelectedCell singleSelectedCell;
grpc::Status singleSelectedCellStatus = assignNextSelectedCell( &singleSelectedCell, eclipseItems );
if ( singleSelectedCellStatus.ok() )
{
rips::SelectedCell* allocSelectedCell = reply->add_cells();
*allocSelectedCell = singleSelectedCell;
}
else
{
break;
}
}
if ( indexInPackage > 0u )
{
return Status::OK;
}
return Status( grpc::OUT_OF_RANGE, "We've reached the end. This is not an error but means transmission is finished" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcCaseService::GetSelectedCells( grpc::ServerContext* context,
const rips::CaseRequest* request,
rips::SelectedCells* reply,
RiaSelectedCellsStateHandler* stateHandler )
{
return stateHandler->assignReply( reply );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcCaseService::GetReservoirBoundingBox( grpc::ServerContext* context,
const rips::CaseRequest* request,
rips::BoundingBox* reply )
{
RimCase* rimCase = findCase( request->id() );
if ( rimCase )
{
cvf::BoundingBox boundingBox = rimCase->reservoirBoundingBox();
reply->set_min_x( boundingBox.min().x() );
reply->set_min_y( boundingBox.min().y() );
reply->set_min_z( boundingBox.min().z() );
reply->set_max_x( boundingBox.max().x() );
reply->set_max_y( boundingBox.max().y() );
reply->set_max_z( boundingBox.max().z() );
return Status::OK;
}
return Status( grpc::NOT_FOUND, "Case not found" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcCaseService::GetCoarseningInfoArray( grpc::ServerContext* context,
const rips::CaseRequest* request,
rips::CoarseningInfoArray* reply )
{
RimEclipseCase* rimCase = dynamic_cast<RimEclipseCase*>( findCase( request->id() ) );
if ( rimCase && rimCase->eclipseCaseData() && rimCase->eclipseCaseData()->mainGrid() )
{
for ( size_t gridIdx = 0; gridIdx < rimCase->eclipseCaseData()->gridCount(); gridIdx++ )
{
RigGridBase* grid = rimCase->eclipseCaseData()->grid( gridIdx );
size_t localCoarseningBoxCount = grid->coarseningBoxCount();
for ( size_t boxIdx = 0; boxIdx < localCoarseningBoxCount; boxIdx++ )
{
size_t i1, i2, j1, j2, k1, k2;
grid->coarseningBox( boxIdx, &i1, &i2, &j1, &j2, &k1, &k2 );
rips::CoarseningInfo* coarseningInfo = reply->add_data();
rips::Vec3i* min = new rips::Vec3i;
min->set_i( (int)i1 );
min->set_j( (int)j1 );
min->set_k( (int)k1 );
coarseningInfo->set_allocated_min( min );
rips::Vec3i* max = new rips::Vec3i;
max->set_i( (int)i2 );
max->set_j( (int)j2 );
max->set_k( (int)k2 );
coarseningInfo->set_allocated_max( max );
}
}
return Status::OK;
}
return Status( grpc::NOT_FOUND, "Case not found" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RiaGrpcCallbackInterface*> RiaGrpcCaseService::createCallbacks()
{
typedef RiaGrpcCaseService Self;
return { new RiaGrpcUnaryCallback<Self, CaseRequest, GridCount>( this, &Self::GetGridCount, &Self::RequestGetGridCount ),
new RiaGrpcUnaryCallback<Self, CellInfoRequest, CellCount>( this, &Self::GetCellCount, &Self::RequestGetCellCount ),
new RiaGrpcUnaryCallback<Self, CaseRequest, TimeStepDates>( this, &Self::GetTimeSteps, &Self::RequestGetTimeSteps ),
new RiaGrpcUnaryCallback<Self, CaseRequest, DaysSinceStart>( this,
&Self::GetDaysSinceStart,
&Self::RequestGetDaysSinceStart ),
new RiaGrpcUnaryCallback<Self, CaseRequest, CaseInfo>( this, &Self::GetCaseInfo, &Self::RequestGetCaseInfo ),
new RiaGrpcUnaryCallback<Self, CaseRequest, PdmObject>( this, &Self::GetPdmObject, &Self::RequestGetPdmObject ),
new RiaGrpcServerToClientStreamCallback<Self,
CellInfoRequest,
CellInfoArray,
RiaActiveCellInfoStateHandler>( this,
&Self::GetCellInfoForActiveCells,
&Self::RequestGetCellInfoForActiveCells,
new RiaActiveCellInfoStateHandler ),
new RiaGrpcServerToClientStreamCallback<Self,
CellInfoRequest,
CellCenters,
RiaActiveCellInfoStateHandler>( this,
&Self::GetCellCenterForActiveCells,
&Self::RequestGetCellCenterForActiveCells,
new RiaActiveCellInfoStateHandler ),
new RiaGrpcServerToClientStreamCallback<Self,
CellInfoRequest,
CellCornersArray,
RiaActiveCellInfoStateHandler>( this,
&Self::GetCellCornersForActiveCells,
&Self::RequestGetCellCornersForActiveCells,
new RiaActiveCellInfoStateHandler ),
new RiaGrpcServerToClientStreamCallback<Self,
CaseRequest,
SelectedCells,
RiaSelectedCellsStateHandler>( this,
&Self::GetSelectedCells,
&Self::RequestGetSelectedCells,
new RiaSelectedCellsStateHandler ),
new RiaGrpcUnaryCallback<Self, CaseRequest, BoundingBox>( this,
&Self::GetReservoirBoundingBox,
&Self::RequestGetReservoirBoundingBox ),
new RiaGrpcUnaryCallback<Self, CaseRequest, CoarseningInfoArray>( this,
&Self::GetCoarseningInfoArray,
&Self::RequestGetCoarseningInfoArray ) };
}
static bool RiaGrpcCaseService_init =
RiaGrpcServiceFactory::instance()->registerCreator<RiaGrpcCaseService>( typeid( RiaGrpcCaseService ).hash_code() );

View File

@@ -0,0 +1,149 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "Case.grpc.pb.h"
#include "RiaGrpcServiceInterface.h"
#include "RiaPorosityModel.h"
#include <vector>
namespace rips
{
class CaseRequest;
class PdmObject;
} // namespace rips
class RiaGrpcCallbackInterface;
class RigCell;
class RigActiveCellInfo;
class RimEclipseCase;
class RiuEclipseSelectionItem;
//==================================================================================================
//
// State handler for streaming of active cell info
//
//==================================================================================================
class RiaActiveCellInfoStateHandler
{
typedef grpc::Status Status;
public:
RiaActiveCellInfoStateHandler();
Status init( const rips::CellInfoRequest* request );
RigActiveCellInfo* activeCellInfo() const;
const std::vector<RigCell>& reservoirCells() const;
// For cell info:
Status assignNextActiveCellInfoData( rips::CellInfo* cellInfo );
void assignCellInfoData( rips::CellInfo* cellInfo, const std::vector<RigCell>& reservoirCells, size_t cellIdx );
Status assignReply( rips::CellInfoArray* reply );
// For cell centers:
Status assignNextActiveCellCenter( rips::Vec3d* cellCenter );
void assignCellCenter( rips::Vec3d* cellCenter, const std::vector<RigCell>& reservoirCells, size_t cellIdx );
Status assignCellCentersReply( rips::CellCenters* reply );
// For cell corners:
Status assignNextActiveCellCorners( rips::CellCorners* cellCorners );
void assignCellCorners( rips::CellCorners* cellCorners, const std::vector<RigCell>& reservoirCells, size_t cellIdx );
Status assignCellCornersReply( rips::CellCornersArray* reply );
protected:
const rips::CellInfoRequest* m_request;
RimEclipseCase* m_eclipseCase;
RiaDefines::PorosityModelType m_porosityModel;
RigActiveCellInfo* m_activeCellInfo;
std::vector<size_t> m_globalCoarseningBoxIndexStart;
size_t m_currentCellIdx;
};
//==================================================================================================
//
// State handler for streaming of selected cells
//
//==================================================================================================
class RiaSelectedCellsStateHandler
{
typedef grpc::Status Status;
public:
RiaSelectedCellsStateHandler();
Status init( const rips::CaseRequest* request );
Status assignReply( rips::SelectedCells* reply );
void assignSelectedCell( rips::SelectedCell* cell, const RiuEclipseSelectionItem* item );
Status assignNextSelectedCell( rips::SelectedCell* cell, const std::vector<RiuEclipseSelectionItem*>& items );
protected:
const rips::CaseRequest* m_request;
RimEclipseCase* m_eclipseCase;
size_t m_currentItem;
};
//==================================================================================================
//
// gRPC-service answering requests about grid information for a given case
//
//==================================================================================================
class RiaGrpcCaseService final : public rips::Case::AsyncService, public RiaGrpcServiceInterface
{
public:
grpc::Status
GetGridCount( grpc::ServerContext* context, const rips::CaseRequest* request, rips::GridCount* reply ) override;
grpc::Status GetCellCount( grpc::ServerContext* context,
const rips::CellInfoRequest* request,
rips::CellCount* reply ) override;
grpc::Status GetTimeSteps( grpc::ServerContext* context,
const rips::CaseRequest* request,
rips::TimeStepDates* reply ) override;
grpc::Status GetDaysSinceStart( grpc::ServerContext* context,
const rips::CaseRequest* request,
rips::DaysSinceStart* reply ) override;
grpc::Status GetCaseInfo( grpc::ServerContext* context, const rips::CaseRequest* request, rips::CaseInfo* reply ) override;
grpc::Status
GetPdmObject( grpc::ServerContext* context, const rips::CaseRequest* request, rips::PdmObject* reply ) override;
grpc::Status GetCellInfoForActiveCells( grpc::ServerContext* context,
const rips::CellInfoRequest* request,
rips::CellInfoArray* reply,
RiaActiveCellInfoStateHandler* stateHandler );
grpc::Status GetCellCenterForActiveCells( grpc::ServerContext* context,
const rips::CellInfoRequest* request,
rips::CellCenters* reply,
RiaActiveCellInfoStateHandler* stateHandler );
grpc::Status GetCellCornersForActiveCells( grpc::ServerContext* context,
const rips::CellInfoRequest* request,
rips::CellCornersArray* reply,
RiaActiveCellInfoStateHandler* stateHandler );
grpc::Status GetSelectedCells( grpc::ServerContext* context,
const rips::CaseRequest* request,
rips::SelectedCells* reply,
RiaSelectedCellsStateHandler* stateHandler );
grpc::Status GetReservoirBoundingBox( grpc::ServerContext* context,
const rips::CaseRequest* request,
rips::BoundingBox* reply ) override;
grpc::Status GetCoarseningInfoArray( grpc::ServerContext* context,
const rips::CaseRequest* request,
rips::CoarseningInfoArray* reply ) override;
std::vector<RiaGrpcCallbackInterface*> createCallbacks() override;
};

View File

@@ -0,0 +1,411 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#include "RiaGrpcCommandService.h"
#include "RiaGrpcCallbacks.h"
#include "RicfReplaceCase.h"
#include "RicfSetTimeStep.h"
#include "cafAssert.h"
#include "cafPdmChildField.h"
#include "cafPdmDataValueField.h"
#include "cafPdmDefaultObjectFactory.h"
#include "cafPdmObject.h"
#include "cafPdmValueField.h"
#include <google/protobuf/reflection.h>
using namespace rips;
using namespace google::protobuf;
// Windows may define GetMessage as a Macro and this is in direct conflict with the gRPC GetMessage calls.
#ifdef WIN32
#ifdef GetMessage
#undef GetMessage
#endif
#endif
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcCommandService::Execute( grpc::ServerContext* context, const CommandParams* request, CommandReply* reply )
{
auto requestDescriptor = request->GetDescriptor();
CommandParams::ParamsCase paramsCase = request->params_case();
if ( paramsCase != CommandParams::PARAMS_NOT_SET )
{
auto grpcOneOfMessage = requestDescriptor->FindFieldByNumber( (int)paramsCase );
CAF_ASSERT( grpcOneOfMessage->type() == FieldDescriptor::TYPE_MESSAGE );
QString grpcOneOfMessageName = QString::fromStdString( grpcOneOfMessage->name() );
auto pdmObjectHandle = caf::PdmDefaultObjectFactory::instance()->create( grpcOneOfMessageName );
auto commandHandle = dynamic_cast<RicfCommandObject*>( pdmObjectHandle );
if ( commandHandle )
{
// Copy parameters
RicfMultiCaseReplace* multiCaseReplaceCommand = dynamic_cast<RicfMultiCaseReplace*>( commandHandle );
if ( multiCaseReplaceCommand )
{
CAF_ASSERT( request->has_replacemultiplecases() );
auto replaceMultipleCasesRequest = request->replacemultiplecases();
std::map<int, QString> caseIdFileMap;
for ( auto caseGridFilePair : replaceMultipleCasesRequest.casepairs() )
{
caseIdFileMap.insert( std::make_pair( caseGridFilePair.caseid(),
QString::fromStdString( caseGridFilePair.newgridfile() ) ) );
}
multiCaseReplaceCommand->setCaseReplacePairs( caseIdFileMap );
}
else
{
assignPdmObjectValues( commandHandle, *request, grpcOneOfMessage );
}
// Execute command
caf::PdmScriptResponse response = commandHandle->execute();
// Copy results
if ( response.status() == caf::PdmScriptResponse::COMMAND_ERROR )
{
return grpc::Status( grpc::FAILED_PRECONDITION, response.sanitizedResponseMessage().toStdString() );
}
else if ( response.status() == caf::PdmScriptResponse::COMMAND_WARNING )
{
context->AddTrailingMetadata( "warning", response.sanitizedResponseMessage().toStdString() );
}
assignResultToReply( response.result(), reply );
return Status::OK;
}
}
return grpc::Status( grpc::NOT_FOUND, "Command not found" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RiaGrpcCallbackInterface*> RiaGrpcCommandService::createCallbacks()
{
typedef RiaGrpcCommandService Self;
return { new RiaGrpcUnaryCallback<Self, CommandParams, CommandReply>( this, &Self::Execute, &Self::RequestExecute ) };
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename T>
caf::PdmField<T>* RiaGrpcCommandService::dataValueField( caf::PdmValueField* valueField )
{
caf::PdmField<T>* dataValField = dynamic_cast<caf::PdmField<T>*>( valueField );
CAF_ASSERT( dataValField );
return dataValField;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <typename T>
const caf::PdmField<T>* RiaGrpcCommandService::constDataValueField( const caf::PdmValueField* valueField )
{
const caf::PdmField<T>* dataValField = dynamic_cast<const caf::PdmField<T>*>( valueField );
CAF_ASSERT( dataValField );
return dataValField;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGrpcCommandService::assignPdmFieldValue( caf::PdmValueField* pdmValueField,
const Message& params,
const FieldDescriptor* paramDescriptor )
{
FieldDescriptor::Type fieldDataType = paramDescriptor->type();
const Reflection* reflection = params.GetReflection();
if ( paramDescriptor->is_repeated() && fieldDataType != FieldDescriptor::TYPE_INT32 &&
fieldDataType != FieldDescriptor::TYPE_STRING )
{
CAF_ASSERT( false && "Only integer and string vectors are implemented as command arguments" );
}
switch ( fieldDataType )
{
case FieldDescriptor::TYPE_BOOL:
{
auto value = reflection->GetBool( params, paramDescriptor );
auto dataField = dataValueField<bool>( pdmValueField );
dataField->setValue( value );
break;
}
case FieldDescriptor::TYPE_INT32:
{
if ( paramDescriptor->is_repeated() )
{
RepeatedFieldRef<int> repeatedField = reflection->GetRepeatedFieldRef<int>( params, paramDescriptor );
auto dataField = dataValueField<std::vector<int>>( pdmValueField );
dataField->setValue( std::vector<int>( repeatedField.begin(), repeatedField.end() ) );
}
else
{
int value = reflection->GetInt32( params, paramDescriptor );
auto dataField = dataValueField<int>( pdmValueField );
dataField->setValue( value );
}
break;
}
case FieldDescriptor::TYPE_UINT32:
{
uint value = reflection->GetUInt32( params, paramDescriptor );
auto dataField = dataValueField<uint>( pdmValueField );
dataField->setValue( value );
break;
}
case FieldDescriptor::TYPE_STRING:
{
if ( paramDescriptor->is_repeated() )
{
RepeatedFieldRef<std::string> repeatedField =
reflection->GetRepeatedFieldRef<std::string>( params, paramDescriptor );
std::vector<QString> stringVector;
for ( const std::string& string : repeatedField )
{
stringVector.push_back( QString::fromStdString( string ) );
}
auto dataField = dataValueField<std::vector<QString>>( pdmValueField );
dataField->setValue( stringVector );
}
else
{
auto value = QString::fromStdString( reflection->GetString( params, paramDescriptor ) );
auto dataField = dataValueField<QString>( pdmValueField );
dataField->setValue( value );
}
break;
}
case FieldDescriptor::TYPE_FLOAT:
{
auto value = reflection->GetFloat( params, paramDescriptor );
auto dataField = dataValueField<float>( pdmValueField );
dataField->setValue( value );
break;
}
case FieldDescriptor::TYPE_DOUBLE:
{
auto value = reflection->GetDouble( params, paramDescriptor );
auto dataField = dataValueField<double>( pdmValueField );
dataField->setValue( value );
break;
}
case FieldDescriptor::TYPE_ENUM:
{
auto value = reflection->GetEnumValue( params, paramDescriptor );
pdmValueField->setFromQVariant( QVariant( value ) );
break;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGrpcCommandService::assignPdmObjectValues( caf::PdmObjectHandle* pdmObjectHandle,
const google::protobuf::Message& params,
const google::protobuf::FieldDescriptor* paramDescriptor )
{
FieldDescriptor::Type fieldDataType = paramDescriptor->type();
const Reflection* reflection = params.GetReflection();
CAF_ASSERT( fieldDataType == FieldDescriptor::TYPE_MESSAGE );
const Message& subMessage = reflection->GetMessage( params, paramDescriptor );
const rips::PdmObject* ripsPdmObject = dynamic_cast<const rips::PdmObject*>( &subMessage );
if ( ripsPdmObject )
{
copyPdmObjectFromRipsToCaf( ripsPdmObject, pdmObjectHandle );
return;
}
auto messageDescriptor = paramDescriptor->message_type();
int numParameters = messageDescriptor->field_count();
for ( int i = 0; i < numParameters; ++i )
{
auto parameter = messageDescriptor->field( i );
if ( parameter )
{
QString parameterName = QString::fromStdString( parameter->name() );
auto pdmChildFieldHandle =
dynamic_cast<caf::PdmChildFieldHandle*>( pdmObjectHandle->findField( parameterName ) );
auto pdmValueFieldHandle = dynamic_cast<caf::PdmValueField*>( pdmObjectHandle->findField( parameterName ) );
if ( pdmChildFieldHandle )
{
std::vector<caf::PdmObjectHandle*> childObjects;
pdmChildFieldHandle->childObjects( &childObjects );
caf::PdmObjectHandle* childObject = nullptr;
CAF_ASSERT( childObjects.size() <= 1u ); // We do not support child array fields yet
if ( childObjects.size() == 1u )
{
childObject = childObjects.front();
}
else if ( childObjects.empty() )
{
childObject = emplaceChildField( pdmChildFieldHandle );
}
CAF_ASSERT( childObject );
if ( childObject )
{
assignPdmObjectValues( childObject, subMessage, parameter );
}
}
else if ( pdmValueFieldHandle )
{
assignPdmFieldValue( pdmValueFieldHandle, subMessage, parameter );
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGrpcCommandService::assignGrpcFieldValue( Message* reply,
const FieldDescriptor* fieldDescriptor,
const caf::PdmValueField* pdmValueField )
{
if ( fieldDescriptor->is_repeated() )
{
auto reflection = reply->GetReflection();
QVariant qValue = pdmValueField->toQVariant();
if ( fieldDescriptor->type() == FieldDescriptor::TYPE_STRING )
{
MutableRepeatedFieldRef<std::string> repeatedField =
reflection->GetMutableRepeatedFieldRef<std::string>( reply, fieldDescriptor );
QStringList stringList = qValue.toStringList();
for ( QString stringValue : stringList )
{
repeatedField.Add( stringValue.toStdString() );
}
}
else
{
CAF_ASSERT( false && "Assigning vector results to Command Results is only implemented for strings" );
}
return;
}
FieldDescriptor::Type fieldDataType = fieldDescriptor->type();
QVariant qValue = pdmValueField->toQVariant();
auto reflection = reply->GetReflection();
switch ( fieldDataType )
{
case FieldDescriptor::TYPE_BOOL:
{
reflection->SetBool( reply, fieldDescriptor, qValue.toBool() );
break;
}
case FieldDescriptor::TYPE_INT32:
{
reflection->SetInt32( reply, fieldDescriptor, qValue.toInt() );
break;
}
case FieldDescriptor::TYPE_UINT32:
{
reflection->SetUInt32( reply, fieldDescriptor, qValue.toUInt() );
break;
}
case FieldDescriptor::TYPE_INT64:
{
reflection->SetInt64( reply, fieldDescriptor, qValue.toLongLong() );
break;
}
case FieldDescriptor::TYPE_UINT64:
{
reflection->SetUInt64( reply, fieldDescriptor, qValue.toULongLong() );
break;
}
case FieldDescriptor::TYPE_STRING:
{
reflection->SetString( reply, fieldDescriptor, qValue.toString().toStdString() );
break;
}
case FieldDescriptor::TYPE_FLOAT:
{
reflection->SetFloat( reply, fieldDescriptor, qValue.toFloat() );
break;
}
case FieldDescriptor::TYPE_DOUBLE:
{
reflection->SetDouble( reply, fieldDescriptor, qValue.toDouble() );
break;
}
case FieldDescriptor::TYPE_ENUM:
{
reflection->SetEnumValue( reply, fieldDescriptor, qValue.toInt() );
break;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGrpcCommandService::assignResultToReply( const caf::PdmObject* result, CommandReply* reply )
{
if ( !result )
{
reply->set_allocated_emptyresult( new Empty );
return;
}
QString resultType = result->classKeyword();
auto replyDescriptor = reply->GetDescriptor();
auto oneofDescriptor = replyDescriptor->FindOneofByName( "result" );
const FieldDescriptor* matchingOneOf = nullptr;
for ( int fieldIndex = 0; fieldIndex < oneofDescriptor->field_count(); ++fieldIndex )
{
auto fieldDescriptor = oneofDescriptor->field( fieldIndex );
if ( fieldDescriptor->name() == resultType.toStdString() )
{
matchingOneOf = fieldDescriptor;
break;
}
}
CAF_ASSERT( matchingOneOf );
Message* message = reply->GetReflection()->MutableMessage( reply, matchingOneOf );
CAF_ASSERT( message );
auto resultDescriptor = message->GetDescriptor();
for ( int fieldIndex = 0; fieldIndex < resultDescriptor->field_count(); ++fieldIndex )
{
auto fieldDescriptor = resultDescriptor->field( fieldIndex );
const auto pdmField = dynamic_cast<const caf::PdmValueField*>(
result->findField( QString::fromStdString( fieldDescriptor->name() ) ) );
assignGrpcFieldValue( message, fieldDescriptor, pdmField );
}
}
static bool RiaGrpcCommandService_init = RiaGrpcServiceFactory::instance()->registerCreator<RiaGrpcCommandService>(
typeid( RiaGrpcCommandService ).hash_code() );

View File

@@ -0,0 +1,71 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RiaGrpcServiceInterface.h"
#include "Commands.grpc.pb.h"
#include <grpcpp/grpcpp.h>
#include <vector>
namespace caf
{
class PdmChildFieldHandle;
class PdmValueField;
class PdmObject;
class PdmObjectHandle;
template <typename T>
class PdmField;
} // namespace caf
namespace google
{
namespace protobuf
{
class FieldDescriptor;
class Message;
} // namespace protobuf
} // namespace google
class RiaGrpcCallbackInterface;
class RiaGrpcCommandService : public rips::Commands::AsyncService, public RiaGrpcServiceInterface
{
public:
grpc::Status
Execute( grpc::ServerContext* context, const rips::CommandParams* request, rips::CommandReply* reply ) override;
std::vector<RiaGrpcCallbackInterface*> createCallbacks() override;
private:
template <typename T>
static caf::PdmField<T>* dataValueField( caf::PdmValueField* valueField );
template <typename T>
static const caf::PdmField<T>* constDataValueField( const caf::PdmValueField* valueField );
void assignPdmFieldValue( caf::PdmValueField* pdmValueField,
const google::protobuf::Message& params,
const google::protobuf::FieldDescriptor* paramDescriptor );
void assignPdmObjectValues( caf::PdmObjectHandle* pdmObject,
const google::protobuf::Message& params,
const google::protobuf::FieldDescriptor* paramDescriptor );
void assignGrpcFieldValue( google::protobuf::Message* reply,
const google::protobuf::FieldDescriptor* fieldDescriptor,
const caf::PdmValueField* pdmValueField );
void assignResultToReply( const caf::PdmObject* result, rips::CommandReply* reply );
};

View File

@@ -0,0 +1,208 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#include "RiaGrpcGridService.h"
#include "RiaGrpcCallbacks.h"
#include "RiaGrpcHelper.h"
#include "RigCell.h"
#include "RigEclipseCaseData.h"
#include "RigMainGrid.h"
#include "RimEclipseCase.h"
using namespace rips;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaCellCenterStateHandler::RiaCellCenterStateHandler()
: m_request( nullptr )
, m_eclipseCase( nullptr )
, m_grid( nullptr )
, m_currentCellIdx( 0u )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaCellCenterStateHandler::init( const rips::GridRequest* request )
{
CAF_ASSERT( request );
m_request = request;
RimCase* rimCase = RiaGrpcServiceInterface::findCase( m_request->case_request().id() );
m_eclipseCase = dynamic_cast<RimEclipseCase*>( rimCase );
if ( !m_eclipseCase )
{
return grpc::Status( grpc::NOT_FOUND, "Eclipse Case not found" );
}
size_t gridIndex = (size_t)request->grid_index();
if ( gridIndex >= m_eclipseCase->mainGrid()->gridCount() )
{
return grpc::Status( grpc::NOT_FOUND, "Grid not found" );
}
m_grid = m_eclipseCase->mainGrid()->gridByIndex( gridIndex );
return grpc::Status::OK;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaCellCenterStateHandler::assignReply( rips::CellCenters* reply )
{
const size_t packageSize = RiaGrpcServiceInterface::numberOfDataUnitsInPackage( sizeof( rips::Vec3d ) );
size_t indexInPackage = 0u;
reply->mutable_centers()->Reserve( (int)packageSize );
for ( ; indexInPackage < packageSize && m_currentCellIdx < m_grid->cellCount(); ++indexInPackage )
{
cvf::Vec3d center = m_grid->cell( m_currentCellIdx ).center();
RiaGrpcHelper::convertVec3dToPositiveDepth( &center );
Vec3d* cellCenter = reply->add_centers();
cellCenter->set_x( center.x() );
cellCenter->set_y( center.y() );
cellCenter->set_z( center.z() );
m_currentCellIdx++;
}
if ( indexInPackage > 0u )
{
return Status::OK;
}
return Status( grpc::OUT_OF_RANGE, "We've reached the end. This is not an error but means transmission is finished" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaCellCenterStateHandler::assignCornersReply( rips::CellCornersArray* reply )
{
const size_t packageSize = RiaGrpcServiceInterface::numberOfDataUnitsInPackage( sizeof( rips::CellCorners ) );
size_t indexInPackage = 0u;
reply->mutable_cells()->Reserve( (int)packageSize );
cvf::Vec3d cornerVerts[8];
for ( ; indexInPackage < packageSize && m_currentCellIdx < m_grid->cellCount(); ++indexInPackage )
{
m_grid->cellCornerVertices( m_currentCellIdx, cornerVerts );
for ( cvf::Vec3d& corner : cornerVerts )
{
RiaGrpcHelper::convertVec3dToPositiveDepth( &corner );
}
rips::CellCorners* corners = reply->add_cells();
RiaGrpcHelper::setCornerValues( corners->mutable_c0(), cornerVerts[0] );
RiaGrpcHelper::setCornerValues( corners->mutable_c1(), cornerVerts[1] );
RiaGrpcHelper::setCornerValues( corners->mutable_c2(), cornerVerts[2] );
RiaGrpcHelper::setCornerValues( corners->mutable_c3(), cornerVerts[3] );
RiaGrpcHelper::setCornerValues( corners->mutable_c4(), cornerVerts[4] );
RiaGrpcHelper::setCornerValues( corners->mutable_c5(), cornerVerts[5] );
RiaGrpcHelper::setCornerValues( corners->mutable_c6(), cornerVerts[6] );
RiaGrpcHelper::setCornerValues( corners->mutable_c7(), cornerVerts[7] );
m_currentCellIdx++;
}
if ( indexInPackage > 0u )
{
return Status::OK;
}
return Status( grpc::OUT_OF_RANGE, "We've reached the end. This is not an error but means transmission is finished" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcGridService::GetDimensions( grpc::ServerContext* context,
const rips::GridRequest* request,
rips::GridDimensions* reply )
{
RimCase* rimCase = findCase( request->case_request().id() );
RimEclipseCase* eclipseCase = dynamic_cast<RimEclipseCase*>( rimCase );
if ( eclipseCase )
{
size_t gridIndex = (size_t)request->grid_index();
if ( gridIndex < eclipseCase->mainGrid()->gridCount() )
{
const RigGridBase* grid = eclipseCase->mainGrid()->gridByIndex( gridIndex );
Vec3i* dimensions = new Vec3i;
dimensions->set_i( (int)grid->cellCountI() );
dimensions->set_j( (int)grid->cellCountJ() );
dimensions->set_k( (int)grid->cellCountK() );
reply->set_allocated_dimensions( dimensions );
return grpc::Status::OK;
}
return grpc::Status( grpc::NOT_FOUND, "Grid not found" );
}
return grpc::Status( grpc::NOT_FOUND, "Eclipse Case not found" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcGridService::GetCellCenters( grpc::ServerContext* context,
const rips::GridRequest* request,
rips::CellCenters* reply,
RiaCellCenterStateHandler* stateHandler )
{
return stateHandler->assignReply( reply );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcGridService::GetCellCorners( grpc::ServerContext* context,
const rips::GridRequest* request,
rips::CellCornersArray* reply,
RiaCellCenterStateHandler* stateHandler )
{
return stateHandler->assignCornersReply( reply );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RiaGrpcCallbackInterface*> RiaGrpcGridService::createCallbacks()
{
typedef RiaGrpcGridService Self;
return {
new RiaGrpcServerToClientStreamCallback<Self, GridRequest, CellCenters, RiaCellCenterStateHandler>( this,
&Self::GetCellCenters,
&Self::RequestGetCellCenters,
new RiaCellCenterStateHandler ),
new RiaGrpcServerToClientStreamCallback<Self, GridRequest, CellCornersArray, RiaCellCenterStateHandler>( this,
&Self::GetCellCorners,
&Self::RequestGetCellCorners,
new RiaCellCenterStateHandler ),
new RiaGrpcUnaryCallback<Self, GridRequest, GridDimensions>( this, &Self::GetDimensions, &Self::RequestGetDimensions ) };
}
static bool RiaGrpcGridService_init =
RiaGrpcServiceFactory::instance()->registerCreator<RiaGrpcGridService>( typeid( RiaGrpcGridService ).hash_code() );

View File

@@ -0,0 +1,76 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2019- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "Grid.grpc.pb.h"
#include "RiaGrpcServiceInterface.h"
#include <vector>
class RigGridBase;
class RimEclipseCase;
namespace rips
{
class GridRequest;
class CellCenters;
class GridDimensions;
}; // namespace rips
//==================================================================================================
//
// State handler for streaming of active cell info
//
//==================================================================================================
class RiaCellCenterStateHandler
{
typedef grpc::Status Status;
public:
RiaCellCenterStateHandler();
grpc::Status init( const rips::GridRequest* request );
grpc::Status assignReply( rips::CellCenters* reply );
grpc::Status assignCornersReply( rips::CellCornersArray* reply );
protected:
const rips::GridRequest* m_request;
RimEclipseCase* m_eclipseCase;
size_t m_currentCellIdx;
const RigGridBase* m_grid;
};
class RiaGrpcGridService final : public rips::Grid::AsyncService, public RiaGrpcServiceInterface
{
public:
grpc::Status GetCellCenters( grpc::ServerContext* context,
const rips::GridRequest* request,
rips::CellCenters* reply,
RiaCellCenterStateHandler* stateHandler );
grpc::Status GetCellCorners( grpc::ServerContext* context,
const rips::GridRequest* request,
rips::CellCornersArray* reply,
RiaCellCenterStateHandler* stateHandler );
grpc::Status GetDimensions( grpc::ServerContext* context,
const rips::GridRequest* request,
rips::GridDimensions* reply ) override;
std::vector<RiaGrpcCallbackInterface*> createCallbacks() override;
};

View File

@@ -0,0 +1,37 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#include "RiaGrpcHelper.h"
//--------------------------------------------------------------------------------------------------
/// Convert internal ResInsight representation of cells with negative depth to positive depth.
//--------------------------------------------------------------------------------------------------
void RiaGrpcHelper::convertVec3dToPositiveDepth( cvf::Vec3d* vec )
{
double& z = vec->z();
z *= -1;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaGrpcHelper::setCornerValues( rips::Vec3d* out, const cvf::Vec3d& in )
{
out->set_x( in.x() );
out->set_y( in.y() );
out->set_z( in.z() );
}

View File

@@ -0,0 +1,34 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "Definitions.grpc.pb.h"
#include "cvfVector3.h"
//==================================================================================================
//
// Various gRPC helper methods
//
//==================================================================================================
class RiaGrpcHelper
{
public:
static void convertVec3dToPositiveDepth( cvf::Vec3d* vec );
static void setCornerValues( rips::Vec3d* out, const cvf::Vec3d& in );
};

View File

@@ -0,0 +1,531 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2020- Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
//////////////////////////////////////////////////////////////////////////////////
#include "RiaGrpcNNCPropertiesService.h"
#include "RiaGrpcCallbacks.h"
#include "RiaGrpcCaseService.h"
#include "RigCaseCellResultsData.h"
#include "RigEclipseCaseData.h"
#include "RigEclipseResultAddress.h"
#include "RigEclipseResultInfo.h"
#include "RigMainGrid.h"
#include "RimEclipseCase.h"
#include "RimEclipseCellColors.h"
#include "RimEclipseInputCase.h"
#include "RimEclipseInputProperty.h"
#include "RimEclipseInputPropertyCollection.h"
#include "RimEclipseView.h"
#include "RimIntersectionCollection.h"
using namespace rips;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaNNCConnectionsStateHandler::RiaNNCConnectionsStateHandler()
: m_request( nullptr )
, m_eclipseCase( nullptr )
, m_currentIdx( 0u )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaNNCConnectionsStateHandler::init( const rips::CaseRequest* request )
{
CAF_ASSERT( request );
m_request = request;
RimCase* rimCase = RiaGrpcServiceInterface::findCase( m_request->id() );
m_eclipseCase = dynamic_cast<RimEclipseCase*>( rimCase );
if ( !( m_eclipseCase && m_eclipseCase->eclipseCaseData() && m_eclipseCase->eclipseCaseData()->mainGrid() ) )
{
return grpc::Status( grpc::NOT_FOUND, "Eclipse Case not found" );
}
return grpc::Status::OK;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
rips::Vec3i* createConnectionVec3i( const RigCell& cell )
{
RigGridBase* hostGrid = cell.hostGrid();
size_t gridLocalCellIndex = cell.gridLocalCellIndex();
size_t i, j, k;
hostGrid->ijkFromCellIndex( gridLocalCellIndex, &i, &j, &k );
rips::Vec3i* vec = new rips::Vec3i;
vec->set_i( i );
vec->set_j( j );
vec->set_k( k );
return vec;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaNNCConnectionsStateHandler::assignReply( rips::NNCConnections* reply )
{
RigMainGrid* mainGrid = m_eclipseCase->eclipseCaseData()->mainGrid();
const RigConnectionContainer& connections = mainGrid->nncData()->connections();
size_t connectionCount = connections.size();
const size_t packageSize = RiaGrpcServiceInterface::numberOfDataUnitsInPackage( sizeof( rips::NNCConnection ) );
size_t indexInPackage = 0u;
reply->mutable_connections()->Reserve( (int)packageSize );
for ( ; indexInPackage < packageSize && m_currentIdx < connectionCount; ++indexInPackage )
{
const RigConnection& connection = connections[m_currentIdx];
const RigCell& cell1 = mainGrid->globalCellArray()[connection.c1GlobIdx()];
const RigCell& cell2 = mainGrid->globalCellArray()[connection.c2GlobIdx()];
NNCConnection* nncConnection = reply->add_connections();
nncConnection->set_allocated_cell1( createConnectionVec3i( cell1 ) );
nncConnection->set_allocated_cell2( createConnectionVec3i( cell2 ) );
nncConnection->set_cell_grid_index1( cell1.hostGrid()->gridIndex() );
nncConnection->set_cell_grid_index2( cell2.hostGrid()->gridIndex() );
m_currentIdx++;
}
if ( indexInPackage > 0u )
{
return Status::OK;
}
return Status( grpc::OUT_OF_RANGE, "We've reached the end. This is not an error but means transmission is finished" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcNNCPropertiesService::GetNNCConnections( grpc::ServerContext* context,
const rips::CaseRequest* request,
rips::NNCConnections* reply,
RiaNNCConnectionsStateHandler* stateHandler )
{
return stateHandler->assignReply( reply );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaNNCValuesStateHandler::RiaNNCValuesStateHandler()
: m_request( nullptr )
, m_eclipseCase( nullptr )
, m_currentIdx( 0u )
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaNNCValuesStateHandler::init( const rips::NNCValuesRequest* request )
{
CAF_ASSERT( request );
m_request = request;
RimCase* rimCase = RiaGrpcServiceInterface::findCase( m_request->case_id() );
m_eclipseCase = dynamic_cast<RimEclipseCase*>( rimCase );
if ( !( m_eclipseCase && m_eclipseCase->eclipseCaseData() && m_eclipseCase->eclipseCaseData()->mainGrid() ) )
{
return grpc::Status( grpc::NOT_FOUND, "Eclipse Case not found" );
}
return grpc::Status::OK;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<double>* getScalarResultByName( const RigNNCData* nncData,
RigNNCData::NNCResultType resultType,
const QString& propertyName,
size_t timeStep )
{
if ( resultType == RigNNCData::NNC_STATIC )
{
return nncData->staticConnectionScalarResultByName( propertyName );
}
if ( resultType == RigNNCData::NNC_DYNAMIC )
{
return nncData->dynamicConnectionScalarResultByName( propertyName, timeStep );
}
if ( resultType == RigNNCData::NNC_GENERATED )
{
return nncData->generatedConnectionScalarResultByName( propertyName, timeStep );
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaNNCValuesStateHandler::assignReply( rips::NNCValues* reply )
{
RigMainGrid* mainGrid = m_eclipseCase->eclipseCaseData()->mainGrid();
auto connections = mainGrid->nncData()->connections();
QString propertyName = QString::fromStdString( m_request->property_name() );
RigNNCData::NNCResultType propertyType = static_cast<RigNNCData::NNCResultType>( m_request->property_type() );
size_t timeStep = m_request->time_step();
const std::vector<double>* nncValues =
getScalarResultByName( mainGrid->nncData(), propertyType, propertyName, timeStep );
if ( !nncValues )
{
return Status( grpc::NOT_FOUND, "No values found" );
}
size_t connectionCount = connections.size();
const size_t packageSize = RiaGrpcServiceInterface::numberOfDataUnitsInPackage( sizeof( double ) );
size_t indexInPackage = 0u;
reply->mutable_values()->Reserve( (int)packageSize );
for ( ; indexInPackage < packageSize && m_currentIdx < connectionCount; ++indexInPackage )
{
reply->add_values( nncValues->at( m_currentIdx ) );
m_currentIdx++;
}
if ( indexInPackage > 0u )
{
return Status::OK;
}
return Status( grpc::OUT_OF_RANGE, "We've reached the end. This is not an error but means transmission is finished" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcNNCPropertiesService::GetNNCValues( grpc::ServerContext* context,
const rips::NNCValuesRequest* request,
rips::NNCValues* reply,
RiaNNCValuesStateHandler* stateHandler )
{
return stateHandler->assignReply( reply );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcNNCPropertiesService::GetAvailableNNCProperties( grpc::ServerContext* context,
const CaseRequest* request,
AvailableNNCProperties* reply )
{
RimEclipseCase* eclipseCase = dynamic_cast<RimEclipseCase*>( RiaGrpcServiceInterface::findCase( request->id() ) );
if ( eclipseCase && eclipseCase->eclipseCaseData() && eclipseCase->eclipseCaseData()->mainGrid() )
{
RigNNCData* nncData = eclipseCase->eclipseCaseData()->mainGrid()->nncData();
std::vector<RigNNCData::NNCResultType> resultTypes;
resultTypes.push_back( RigNNCData::NNC_DYNAMIC );
resultTypes.push_back( RigNNCData::NNC_STATIC );
resultTypes.push_back( RigNNCData::NNC_GENERATED );
for ( size_t rtIdx = 0; rtIdx < resultTypes.size(); ++rtIdx )
{
std::vector<QString> availableParameters = nncData->availableProperties( resultTypes[rtIdx] );
for ( const QString& parameter : availableParameters )
{
AvailableNNCProperty* property = reply->add_properties();
property->set_name( parameter.toStdString() );
property->set_property_type( static_cast<NNCPropertyType>( resultTypes[rtIdx] ) );
}
}
return grpc::Status::OK;
}
return grpc::Status( grpc::NOT_FOUND, "No such case" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
static bool scalarResultExistsOrCreate( RigCaseCellResultsData* results, QString propertyName )
{
RigEclipseResultAddress resAddr( RiaDefines::ResultCatType::GENERATED, propertyName );
if ( !results->ensureKnownResultLoaded( resAddr ) )
{
results->createResultEntry( resAddr, true );
}
std::vector<std::vector<double>>* scalarResultFrames = results->modifiableCellScalarResultTimesteps( resAddr );
size_t timeStepCount = results->maxTimeStepCount();
scalarResultFrames->resize( timeStepCount );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
static bool createIJKCellResults( RigCaseCellResultsData* results, QString propertyName )
{
bool ok;
ok = scalarResultExistsOrCreate( results, QString( "%1IJK" ).arg( propertyName ) );
if ( !ok ) return false;
ok = scalarResultExistsOrCreate( results, QString( "%1I" ).arg( propertyName ) );
if ( !ok ) return false;
ok = scalarResultExistsOrCreate( results, QString( "%1J" ).arg( propertyName ) );
if ( !ok ) return false;
ok = scalarResultExistsOrCreate( results, QString( "%1K" ).arg( propertyName ) );
return ok;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaNNCInputValuesStateHandler::RiaNNCInputValuesStateHandler( bool )
: m_eclipseCase( nullptr )
, m_streamedValueCount( 0u )
, m_cellCount( 0u )
, m_timeStep( 0u )
{
}
std::vector<double>* getOrCreateConnectionScalarResultByName( RigNNCData* nncData, const QString propertyName, int timeStep )
{
std::vector<double>* resultsToAdd = nncData->generatedConnectionScalarResultByName( propertyName, timeStep );
if ( resultsToAdd )
{
return resultsToAdd;
}
else
{
nncData->makeGeneratedConnectionScalarResult( propertyName, timeStep + 1 );
return nncData->generatedConnectionScalarResultByName( propertyName, timeStep );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaNNCInputValuesStateHandler::init( const NNCValuesInputRequest* request )
{
int caseId = request->case_id();
m_eclipseCase = dynamic_cast<RimEclipseCase*>( RiaGrpcServiceInterface::findCase( caseId ) );
if ( m_eclipseCase && m_eclipseCase->eclipseCaseData() && m_eclipseCase->eclipseCaseData()->mainGrid() )
{
auto caseData = m_eclipseCase->eclipseCaseData();
auto m_porosityModel = static_cast<RiaDefines::PorosityModelType>( request->porosity_model() );
m_timeStep = request->time_step();
m_propertyName = QString::fromStdString( request->property_name() );
RigNNCData* nncData = m_eclipseCase->eclipseCaseData()->mainGrid()->nncData();
std::vector<double>* resultsToAdd = getOrCreateConnectionScalarResultByName( nncData, m_propertyName, m_timeStep );
if ( !resultsToAdd )
{
return grpc::Status( grpc::NOT_FOUND, "No results for scalar results found." );
}
if ( !m_eclipseCase->results( m_porosityModel ) )
{
return grpc::Status( grpc::NOT_FOUND, "No results for porosity model." );
}
bool ok = createIJKCellResults( m_eclipseCase->results( m_porosityModel ), m_propertyName );
if ( !ok )
{
return grpc::Status( grpc::NOT_FOUND, "Could not find the property results." );
}
RigEclipseResultAddress resAddr( QString( "%1IJK" ).arg( m_propertyName ) );
m_eclipseCase->results( m_porosityModel )->ensureKnownResultLoaded( resAddr );
nncData->setEclResultAddress( m_propertyName, resAddr );
m_cellCount = caseData->mainGrid()->nncData()->connections().size();
resultsToAdd->resize( m_cellCount, HUGE_VAL );
return Status::OK;
}
return grpc::Status( grpc::NOT_FOUND, "Couldn't find an Eclipse case matching the case Id" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaNNCInputValuesStateHandler::init( const rips::NNCValuesChunk* chunk )
{
if ( chunk->has_params() )
{
return init( &( chunk->params() ) );
}
return grpc::Status( grpc::INVALID_ARGUMENT, "Need to have PropertyRequest parameters in first message" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaNNCInputValuesStateHandler::receiveStreamRequest( const NNCValuesChunk* request,
ClientToServerStreamReply* reply )
{
if ( request->has_values() )
{
auto values = request->values().values();
if ( !values.empty() )
{
RigNNCData* nncData = m_eclipseCase->eclipseCaseData()->mainGrid()->nncData();
std::vector<std::vector<double>>* resultsToAdd =
nncData->generatedConnectionScalarResultByName( m_propertyName );
size_t currentCellIdx = m_streamedValueCount;
m_streamedValueCount += values.size();
for ( int i = 0; i < values.size() && currentCellIdx < m_cellCount; ++i, ++currentCellIdx )
{
resultsToAdd->at( m_timeStep )[currentCellIdx] = values[i];
}
if ( m_streamedValueCount > m_cellCount )
{
return grpc::Status( grpc::OUT_OF_RANGE, "Attempting to write out of bounds" );
}
reply->set_accepted_value_count( static_cast<int64_t>( currentCellIdx ) );
return Status::OK;
}
}
return Status::OK;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RiaNNCInputValuesStateHandler::totalValueCount() const
{
return m_cellCount;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RiaNNCInputValuesStateHandler::streamedValueCount() const
{
return m_streamedValueCount;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RiaNNCInputValuesStateHandler::finish()
{
if ( m_eclipseCase != nullptr )
{
// Create a new input property if we have an input reservoir
RimEclipseInputCase* inputRes = dynamic_cast<RimEclipseInputCase*>( m_eclipseCase );
if ( inputRes )
{
RimEclipseInputProperty* inputProperty =
inputRes->inputPropertyCollection()->findInputProperty( m_propertyName );
if ( !inputProperty )
{
inputProperty = new RimEclipseInputProperty;
inputProperty->resultName = m_propertyName;
inputProperty->eclipseKeyword = "";
inputProperty->fileName = QString( "" );
inputRes->inputPropertyCollection()->inputProperties.push_back( inputProperty );
inputRes->inputPropertyCollection()->updateConnectedEditors();
}
inputProperty->resolvedState = RimEclipseInputProperty::RESOLVED_NOT_SAVED;
}
for ( size_t i = 0; i < m_eclipseCase->reservoirViews.size(); ++i )
{
if ( m_eclipseCase->reservoirViews[i] )
{
// As new result might have been introduced, update all editors connected
m_eclipseCase->reservoirViews[i]->cellResult()->updateConnectedEditors();
// It is usually not needed to create new display model, but if any derived geometry based on
// generated data (from Octave) a full display model rebuild is required
m_eclipseCase->reservoirViews[i]->scheduleCreateDisplayModelAndRedraw();
m_eclipseCase->reservoirViews[i]->intersectionCollection()->scheduleCreateDisplayModelAndRedraw2dIntersectionViews();
}
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
grpc::Status RiaGrpcNNCPropertiesService::SetNNCValues( grpc::ServerContext* context,
const rips::NNCValuesChunk* chunk,
rips::ClientToServerStreamReply* reply,
RiaNNCInputValuesStateHandler* stateHandler )
{
return stateHandler->receiveStreamRequest( chunk, reply );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RiaGrpcCallbackInterface*> RiaGrpcNNCPropertiesService::createCallbacks()
{
typedef RiaGrpcNNCPropertiesService Self;
std::vector<RiaGrpcCallbackInterface*> callbacks;
callbacks =
{ new RiaGrpcUnaryCallback<Self, CaseRequest, AvailableNNCProperties>( this,
&Self::GetAvailableNNCProperties,
&Self::RequestGetAvailableNNCProperties ),
new RiaGrpcServerToClientStreamCallback<Self,
CaseRequest,
rips::NNCConnections,
RiaNNCConnectionsStateHandler>( this,
&Self::GetNNCConnections,
&Self::RequestGetNNCConnections,
new RiaNNCConnectionsStateHandler ),
new RiaGrpcServerToClientStreamCallback<Self,
NNCValuesRequest,
rips::NNCValues,
RiaNNCValuesStateHandler>( this,
&Self::GetNNCValues,
&Self::RequestGetNNCValues,
new RiaNNCValuesStateHandler ),
new RiaGrpcClientToServerStreamCallback<Self,
NNCValuesChunk,
ClientToServerStreamReply,
RiaNNCInputValuesStateHandler>( this,
&Self::SetNNCValues,
&Self::RequestSetNNCValues,
new RiaNNCInputValuesStateHandler(
true ) ) };
return callbacks;
}
static bool RiaGrpcNNCPropertiesService_init =
RiaGrpcServiceFactory::instance()->registerCreator<RiaGrpcNNCPropertiesService>(
typeid( RiaGrpcNNCPropertiesService ).hash_code() );

Some files were not shown because too many files have changed in this diff Show More