#4457 Python: clean up grpc api, Python client API and make installable python package (#4456)

* gRPC: Make names more consistent

* gRPC: clean up case info and improve Python API for cases

* gRPC: much more object oriented Python interface

* Python: Make a proper pip-installable package

* Update rips Python package to auto generate setup.py with version number

* Python: add setup.py to gitignore

* Python: Update Python RIPS interface

* gRPC: Remove example client from cmake file and unit test

* gRPC: Fix up unit test after merge and hide warnings

* gRPC: fix up python client code
This commit is contained in:
Gaute Lindkvist
2019-06-03 14:33:16 +02:00
committed by GitHub
parent 936fab3e32
commit a468532d7f
50 changed files with 1058 additions and 698 deletions

View File

@@ -1,3 +1,7 @@
__pycache__
.pytest_cache
generated
generated
dist
build
rips.egg-info
setup.py

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,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

@@ -1,302 +0,0 @@
from __future__ import print_function
import grpc
import os
import sys
import socket
import logging
sys.path.insert(1, os.path.join(sys.path[0], '../generated'))
from Empty_pb2 import Empty
import CaseInfo_pb2
import CaseInfo_pb2_grpc
import Commands_pb2 as Cmd
import Commands_pb2_grpc as CmdRpc
import GridInfo_pb2
import GridInfo_pb2_grpc
import ProjectInfo_pb2
import ProjectInfo_pb2_grpc
import ResInfo_pb2
import ResInfo_pb2_grpc
import Properties_pb2
import Properties_pb2_grpc
import RiaVersionInfo
class ResInfo:
def __init__(self, channel):
self.resInfo = ResInfo_pb2_grpc.ResInfoStub(channel)
def versionMessage(self):
return self.resInfo.GetVersion(Empty())
def majorVersion(self):
return self.versionMessage().major_version
def minorVersion(self):
return self.versionMessage().minor_version
def patchVersion(self):
return self.versionMessage().patch_version
def versionString(self):
return str(self.majorVersion()) + "." + str(self.minorVersion()) + "." + str(self.patchVersion())
class CommandExecutor:
def __init__(self, channel):
self.commands = CmdRpc.CommandsStub(channel)
def execute(self, commandParams):
try:
return self.commands.Execute(commandParams)
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.NOT_FOUND:
print("Command not found")
else:
print("Other error")
def setTimeStep(self, caseId, timeStep):
return self.execute(Cmd.CommandParams(setTimeStep=Cmd.SetTimeStepParams(caseId=caseId, timeStep=timeStep)))
def setMainWindowSize(self, width, height):
return self.execute(Cmd.CommandParams(setMainWindowSize=Cmd.SetMainWindowSizeParams(width=width, height=height)))
def openProject(self, path):
return self.execute(Cmd.CommandParams(openProject=Cmd.FilePathRequest(path=path)))
def loadCase(self, path):
commandReply = self.execute(Cmd.CommandParams(loadCase=Cmd.FilePathRequest(path=path)))
assert commandReply.HasField("loadCaseResult")
return commandReply.loadCaseResult.id
def closeProject(self):
return self.execute(Cmd.CommandParams(closeProject=Empty()))
def exportWellPaths(self, wellPaths=[], mdStepSize=5.0):
if isinstance(wellPaths, str):
wellPathArray = [str]
elif isinstance(wellPaths, list):
wellPathArray = wellPaths
return self.execute(Cmd.CommandParams(exportWellPaths=Cmd.ExportWellPathRequest(wellPathNames=wellPathArray, mdStepSize=mdStepSize)))
class GridInfo:
def __init__(self, channel):
self.gridInfo = GridInfo_pb2_grpc.GridInfoStub(channel)
def gridCount(self, caseId=0):
return self.gridInfo.GetGridCount(CaseInfo_pb2.Case(id=caseId)).count
def gridDimensions(self, caseId=0):
return self.gridInfo.GetGridDimensions(CaseInfo_pb2.Case(id=caseId)).dimensions
def cellCount(self, caseId=0, porosityModel='MATRIX_MODEL'):
porosityModelEnum = GridInfo_pb2.PorosityModelType.Value(porosityModel)
request = GridInfo_pb2.CellInfoRequest(case_id=caseId,
porosity_model=porosityModel)
return self.gridInfo.GetCellCount(request)
def cellInfoForActiveCells(self, caseId=0, porosityModel='MATRIX_MODEL'):
porosityModelEnum = GridInfo_pb2.PorosityModelType.Value(porosityModel)
request = GridInfo_pb2.CellInfoRequest(case_id=caseId,
porosity_model=porosityModel)
return self.gridInfo.GetCellInfoForActiveCells(request)
def timeSteps(self, caseId=0):
return self.gridInfo.GetTimeSteps(CaseInfo_pb2.Case(id=caseId))
class ProjectInfo:
def __init__(self, channel):
self.projectInfo = ProjectInfo_pb2_grpc.ProjectInfoStub(channel)
def selectedCases(self):
selected = self.projectInfo.SelectedCases(Empty())
if selected is not None:
return selected.case_info
else:
return None
def allCases(self):
cases = self.projectInfo.AllCases(Empty())
if cases is not None:
return cases.case_info
else:
return None
class Properties:
def __init__(self, channel):
self.properties = Properties_pb2_grpc.PropertiesStub(channel)
def generateResultRequestArrayIterator(self, values_iterator, parameters):
chunk = Properties_pb2.ResultRequestChunk()
chunk.params.CopyFrom(parameters)
yield chunk
for values in values_iterator:
valmsg = Properties_pb2.ResultArray(values = values)
chunk.values.CopyFrom(valmsg)
yield chunk
def generateResultRequestChunks(self, array, parameters):
# Each double is 8 bytes. A good chunk size is 64KiB = 65536B
# Meaning ideal number of doubles would be 8192.
# However we need overhead space, so if we choose 8160 in chunk size
# We have 256B left for overhead which should be plenty
chunkSize = 8000
index = -1
while index < len(array):
chunk = Properties_pb2.ResultRequestChunk()
if index is -1:
chunk.params.CopyFrom(parameters)
index += 1;
else:
actualChunkSize = min(len(array) - index + 1, chunkSize)
chunk.values.CopyFrom(Properties_pb2.ResultArray(values = array[index:index+actualChunkSize]))
index += actualChunkSize
yield chunk
# Final empty message to signal completion
chunk = Properties_pb2.ResultRequestChunk()
yield chunk
def availableProperties(self, caseId, propertyType, porosityModel = 'MATRIX_MODEL'):
propertyTypeEnum = Properties_pb2.PropertyType.Value(propertyType)
porosityModelEnum = GridInfo_pb2.PorosityModelType.Value(porosityModel)
request = Properties_pb2.PropertiesRequest (request_case = CaseInfo_pb2.Case(id=caseId),
property_type = propertyTypeEnum,
porosity_model = porosityModelEnum)
return self.properties.GetAvailableProperties(request).property_names
def activeCellResults(self, caseId, propertyType, propertyName, timeStep, porosityModel = 'MATRIX_MODEL'):
propertyTypeEnum = Properties_pb2.PropertyType.Value(propertyType)
porosityModelEnum = GridInfo_pb2.PorosityModelType.Value(porosityModel)
request = Properties_pb2.ResultRequest(request_case = CaseInfo_pb2.Case(id=caseId),
property_type = propertyTypeEnum,
property_name = propertyName,
time_step = timeStep,
porosity_model = porosityModelEnum)
for chunk in self.properties.GetActiveCellResults(request):
yield chunk
def gridCellResults(self, caseId, propertyType, propertyName, timeStep, gridIndex = 0, porosityModel = 'MATRIX_MODEL'):
propertyTypeEnum = Properties_pb2.PropertyType.Value(propertyType)
porosityModelEnum = GridInfo_pb2.PorosityModelType.Value(porosityModel)
request = Properties_pb2.ResultRequest(request_case = CaseInfo_pb2.Case(id=caseId),
property_type = propertyTypeEnum,
property_name = propertyName,
time_step = timeStep,
grid_index = gridIndex,
porosity_model = porosityModelEnum)
return self.properties.GetGridResults(request)
def setActiveCellResultsAsync(self, values_iterator, caseId, propertyType, propertyName, timeStep, gridIndex = 0, porosityModel = 'MATRIX_MODEL'):
propertyTypeEnum = Properties_pb2.PropertyType.Value(propertyType)
porosityModelEnum = GridInfo_pb2.PorosityModelType.Value(porosityModel)
request = Properties_pb2.ResultRequest(request_case = CaseInfo_pb2.Case(id=caseId),
property_type = propertyTypeEnum,
property_name = propertyName,
time_step = timeStep,
grid_index = gridIndex,
porosity_model = porosityModelEnum)
try:
reply_iterator = self.generateResultRequestArrayIterator(values_iterator, request)
self.properties.SetActiveCellResults(reply_iterator)
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.NOT_FOUND:
print("Command not found")
else:
print("Other error", e)
def setActiveCellResults(self, values, caseId, propertyType, propertyName, timeStep, gridIndex = 0, porosityModel = 'MATRIX_MODEL'):
propertyTypeEnum = Properties_pb2.PropertyType.Value(propertyType)
porosityModelEnum = GridInfo_pb2.PorosityModelType.Value(porosityModel)
request = Properties_pb2.ResultRequest(request_case = CaseInfo_pb2.Case(id=caseId),
property_type = propertyTypeEnum,
property_name = propertyName,
time_step = timeStep,
grid_index = gridIndex,
porosity_model = porosityModelEnum)
try:
request_iterator = self.generateResultRequestChunks(values, request)
self.properties.SetActiveCellResults(request_iterator)
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.NOT_FOUND:
print("Command not found")
else:
print("Other error", e)
def setGridResults(self, values, caseId, propertyType, propertyName, timeStep, gridIndex = 0, porosityModel = 'MATRIX_MODEL'):
propertyTypeEnum = Properties_pb2.PropertyType.Value(propertyType)
porosityModelEnum = GridInfo_pb2.PorosityModelType.Value(porosityModel)
request = Properties_pb2.ResultRequest(request_case = CaseInfo_pb2.Case(id=caseId),
property_type = propertyTypeEnum,
property_name = propertyName,
time_step = timeStep,
grid_index = gridIndex,
porosity_model = porosityModelEnum)
try:
request_iterator = self.generateResultRequestArrays(values, request)
self.properties.SetGridResults(request_iterator)
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.NOT_FOUND:
print("Command not found")
else:
print("Other error", e)
class Instance:
@staticmethod
def is_port_in_use(port):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(0.2)
return s.connect_ex(('localhost', port)) == 0
@staticmethod
def launch():
port = 50051
portEnv = os.environ.get('RESINSIGHT_GRPC_PORT')
if portEnv:
port = int(portEnv)
resInsightExecutable = os.environ.get('RESINSIGHT_EXECUTABLE')
if resInsightExecutable is None:
print('Error: Could not launch any ResInsight instances because RESINSIGHT_EXECUTABLE is not set')
return None
while Instance.is_port_in_use(port):
port += 1
print('Port ' + str(port))
print('Trying to launch', resInsightExecutable)
pid = os.spawnl(os.P_NOWAIT, resInsightExecutable, " --grpcserver " + str(port))
print(pid)
return Instance(port)
@staticmethod
def find(startPort = 50051, endPort = 50071):
portEnv = os.environ.get('RESINSIGHT_GRPC_PORT')
if portEnv:
startPort = int(portEnv)
endPort = startPort + 20
for tryPort in range(startPort, endPort):
if Instance.is_port_in_use(tryPort):
return Instance(tryPort)
print('Error: Could not find any ResInsight instances responding between ports ' + str(startPort) + ' and ' + str(endPort))
return None
def __init__(self, port = 50051):
logging.basicConfig()
location = "localhost:" + str(port)
self.channel = grpc.insecure_channel(location)
# Main version check package
self.resInfo = ResInfo(self.channel)
try:
majorVersionOk = self.resInfo.majorVersion() == int(RiaVersionInfo.RESINSIGHT_MAJOR_VERSION)
minorVersionOk = self.resInfo.minorVersion() == int(RiaVersionInfo.RESINSIGHT_MINOR_VERSION)
if not (majorVersionOk and minorVersionOk):
raise Exception('Version of ResInsight does not match version of Python API')
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.UNAVAILABLE:
print('Info: Could not find any instances at port ' + str(port))
except Exception as e:
print('Error:', e)
# Service packages
self.commands = CommandExecutor(self.channel)
self.gridInfo = GridInfo(self.channel)
self.projectInfo = ProjectInfo(self.channel)
self.properties = Properties(self.channel)

View File

@@ -1,13 +1,11 @@
import sys
import os
sys.path.insert(1, os.path.join(sys.path[0], '../api'))
import rips
import ResInsight
resInsight = ResInsight.Instance.find()
resInsight = rips.Instance.find()
if resInsight is not None:
caseInfos = resInsight.projectInfo.allCases()
print ("Got " + str(len(caseInfos)) + " cases: ")
for caseInfo in caseInfos:
print(caseInfo.name)
cases = resInsight.project.cases()
print ("Got " + str(len(cases)) + " cases: ")
for case in cases:
print(case.name)

View File

@@ -7,10 +7,12 @@ resInsight = ResInsight.Instance.find()
#gridCount = resInsight.gridInfo.getGridCount(caseId=0)
#gridDimensions = resInsight.gridInfo.getAllGridDimensions(caseId=0)
cellCounts = resInsight.gridInfo.cellCount(caseId=0)
case = resInsight.project.case(id = 0)
cellCounts = case.cellCount()
print("Number of active cells: " + str(cellCounts.active_cell_count))
activeCellInfoChunks = resInsight.gridInfo.cellInfoForActiveCells(caseId=0)
activeCellInfoChunks = case.cellInfoForActiveCells()
#print("Number of grids: " + str(gridCount))
#print(gridDimensions)

View File

@@ -0,0 +1,18 @@
import sys
import os
sys.path.insert(1, os.path.join(sys.path[0], '../api'))
import ResInsight
resInsight = ResInsight.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

@@ -11,12 +11,12 @@ def createResult(poroChunks, permxChunks):
yield resultChunk
resInsight = ResInsight.Instance.find()
case = resInsight.project.case(id=0)
poroChunks = resInsight.properties.activeCellResults(0, 'STATIC_NATIVE', 'PORO', 0)
permxChunks = resInsight.properties.activeCellResults(0, 'STATIC_NATIVE', 'PERMX', 0)
poroChunks = case.properties.activeCellProperty('STATIC_NATIVE', 'PORO', 0)
permxChunks = case.properties.activeCellProperty('STATIC_NATIVE', 'PERMX', 0)
resInsight.properties.setActiveCellResultsAsync(createResult(poroChunks, permxChunks), 0, 'GENERATED', 'POROPERMXAS', 0)
case.properties.setActiveCellPropertyAsync(createResult(poroChunks, permxChunks), 'GENERATED', 'POROPERMXAS', 0)
print("Transferred all results back")

View File

@@ -4,26 +4,25 @@ sys.path.insert(1, os.path.join(sys.path[0], '../api'))
import ResInsight
resInsight = ResInsight.Instance.find()
#gridCount = resInsight.gridInfo.getGridCount(caseId=0)
#gridDimensions = resInsight.gridInfo.getAllGridDimensions(caseId=0)
for i in range(0, 40):
poroChunks = resInsight.properties.activeCellResults(0, 'STATIC_NATIVE', 'PORO', 0)
poroResults = []
for poroChunk in poroChunks:
for poro in poroChunk.values:
poroResults.append(poro)
case = resInsight.project.case(id=0)
permxChunks = resInsight.properties.activeCellResults(0, 'STATIC_NATIVE', 'PERMX', 0)
permxResults = []
for permxChunk in permxChunks:
for permx in permxChunk.values:
permxResults.append(permx)
poroChunks = case.properties.activeCellProperty('STATIC_NATIVE', 'PORO', 0)
poroResults = []
for poroChunk in poroChunks:
for poro in poroChunk.values:
poroResults.append(poro)
results = []
for (poro, permx) in zip(poroResults, permxResults):
results.append(poro * permx)
permxChunks = case.properties.activeCellProperty('STATIC_NATIVE', 'PERMX', 0)
permxResults = []
for permxChunk in permxChunks:
for permx in permxChunk.values:
permxResults.append(permx)
resInsight.properties.setActiveCellResults(results, 0, 'GENERATED', 'POROPERMXSY', 0)
results = []
for (poro, permx) in zip(poroResults, permxResults):
results.append(poro * permx)
case.properties.setActiveCellProperty(results, 'GENERATED', 'POROPERMXSY', 0)
print("Transferred all results back")

View File

@@ -1,28 +0,0 @@
import sys
import os
sys.path.insert(1, os.path.join(sys.path[0], '../api'))
import ResInsight
resInsight = ResInsight.Instance.find()
#gridCount = resInsight.gridInfo.getGridCount(caseId=0)
#gridDimensions = resInsight.gridInfo.getAllGridDimensions(caseId=0)
poroChunks = resInsight.properties.activeCellResults(0, 'STATIC_NATIVE', 'PORO', 0)
poroResults = []
for poroChunk in poroChunks:
for poro in poroChunk.values:
poroResults.append(poro)
permxChunks = resInsight.properties.activeCellResults(0, 'STATIC_NATIVE', 'PERMX', 0)
permxResults = []
for permxChunk in permxChunks:
for permx in permxChunk.values:
permxResults.append(permx)
results = []
for (poro, permx) in zip(poroResults, permxResults):
results.append(poro * permx)
print("Transferred " + str(len(results)) + " cell results")
print("30th active cell: ")
print(results[29])

View File

@@ -6,9 +6,12 @@ import ResInsight
resInsight = ResInsight.Instance.find()
if resInsight is not None:
caseInfos = resInsight.projectInfo.selectedCases()
cases = resInsight.project.selectedCases()
print ("Got " + str(len(cases)) + " cases: ")
for case in cases:
print(case.name)
for property in case.properties.available('DYNAMIC_NATIVE'):
print(property)
print ("Got " + str(len(caseInfos)) + " cases: ")
for caseInfo in caseInfos:
print(caseInfo.name)

View File

@@ -1,19 +0,0 @@
import sys
import os
sys.path.insert(1, os.path.join(sys.path[0], '../api'))
import ResInsight
resInsight = ResInsight.Instance.find()
activeCellCount = resInsight.gridInfo.cellCount(caseId=0).active_cell_count
values = []
for i in range(0, activeCellCount):
values.append(i % 2 * 0.5);
timeSteps = resInsight.gridInfo.timeSteps(caseId=0)
for i in range(0, len(timeSteps.date)):
print("Applying values to all time step " + str(i))
resInsight.properties.setActiveCellResults(values, 0, 'DYNAMIC_NATIVE', 'SOIL', i)

View File

@@ -5,12 +5,13 @@ import ResInsight
resInsight = ResInsight.Instance.find()
totalCellCount = resInsight.gridInfo.cellCount(caseId=0).reservoir_cell_count
case = resInsight.project.case(id=0)
totalCellCount = case.cellCount().reservoir_cell_count
values = []
for i in range(0, totalCellCount):
values.append(i % 2 * 0.75);
print("Applying values to full grid")
resInsight.properties.setGridResults(values, 0, 'DYNAMIC_NATIVE', 'SOIL', 0)
case.properties.setGridProperty(values, 'DYNAMIC_NATIVE', 'SOIL', 0)

View File

@@ -14,18 +14,18 @@ def createResult(soilChunks, porvChunks):
resInsight = ResInsight.Instance.find()
resInsight = ResInsight.Instance.find()
case = resInsight.project.case(id=0)
timeStepInfo = case.timeSteps()
timeStepInfo = resInsight.gridInfo.timeSteps(0)
porvChunks = resInsight.properties.activeCellResults(0, 'STATIC_NATIVE', 'PORV', 0)
porvChunks = case.properties.activeCellProperty('STATIC_NATIVE', 'PORV', 0)
porvArray = []
for porvChunk in porvChunks:
porvArray.append(porvChunk)
for i in range (0, len(timeStepInfo.date)):
soilChunks = resInsight.properties.activeCellResults(0, 'DYNAMIC_NATIVE', 'SOIL', i)
for i in range (0, len(timeStepInfo.dates)):
soilChunks = case.properties.activeCellProperty('DYNAMIC_NATIVE', 'SOIL', i)
input_iterator = createResult(soilChunks, iter(porvArray))
resInsight.properties.setActiveCellResultsAsync(input_iterator, 0, 'GENERATED', 'SOILPORVAsync', i)
case.properties.setActiveCellPropertyAsync(input_iterator, 'GENERATED', 'SOILPORVAsync', i)
print("Transferred all results back")

View File

@@ -3,20 +3,19 @@ import os
sys.path.insert(1, os.path.join(sys.path[0], '../api'))
import ResInsight
resInsight = ResInsight.Instance.find()
#gridCount = resInsight.gridInfo.getGridCount(caseId=0)
#gridDimensions = resInsight.gridInfo.getAllGridDimensions(caseId=0)
resInsight = ResInsight.Instance.find()
case = resInsight.case(id=0)
porvChunks = resInsight.properties.activeCellResults(0, 'STATIC_NATIVE', 'PORV', 0)
porvChunks = case.properties.activeCellProperty('STATIC_NATIVE', 'PORV', 0)
porvResults = []
for porvChunk in porvChunks:
for porv in porvChunk.values:
porvResults.append(porv)
timeStepInfo = resInsight.gridInfo.timeSteps(0)
timeStepInfo = case.timeSteps()
for i in range (0, len(timeStepInfo.date)):
soilChunks = resInsight.properties.activeCellResults(0, 'DYNAMIC_NATIVE', 'SOIL', i)
for i in range (0, len(timeStepInfo.dates)):
soilChunks = case.properties.activeCellProperty('DYNAMIC_NATIVE', 'SOIL', i)
soilResults = []
for soilChunk in soilChunks:
for soil in soilChunk.values:
@@ -25,5 +24,5 @@ for i in range (0, len(timeStepInfo.date)):
for (soil, porv) in zip(soilResults, porvResults):
results.append(soil * porv)
resInsight.properties.setActiveCellResults(results, 0, 'GENERATED', 'SOILPORVSync', i)
case.properties.setActiveCellProperty(results, 'GENERATED', 'SOILPORVSync', i)
print("Transferred all results back")

View File

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

View File

@@ -0,0 +1,25 @@
import grpc
import os
import sys
sys.path.insert(1, os.path.join(sys.path[0], '../generated'))
from Empty_pb2 import Empty
import AppInfo_pb2
import AppInfo_pb2_grpc
class AppInfo:
def __init__(self, channel):
self.appInfo = AppInfo_pb2_grpc.AppInfoStub(channel)
def versionMessage(self):
return self.appInfo.GetVersion(Empty())
def majorVersion(self):
return self.versionMessage().major_version
def minorVersion(self):
return self.versionMessage().minor_version
def patchVersion(self):
return self.versionMessage().patch_version
def versionString(self):
return str(self.majorVersion()) + "." + str(self.minorVersion()) + "." + str(self.patchVersion())

View File

@@ -0,0 +1,56 @@
import grpc
import os
import sys
from .Grid import Grid
from .Properties import Properties
sys.path.insert(1, os.path.join(sys.path[0], '../generated'))
import Case_pb2
import Case_pb2_grpc
class Case:
def __init__(self, channel, id):
self.channel = channel
self.stub = Case_pb2_grpc.CaseStub(channel)
self.id = id
info = self.stub.GetCaseInfo(Case_pb2.CaseRequest(id=self.id))
self.name = info.name
self.groupId = info.group_id
self.type = info.type
self.properties = Properties(self)
self.request = Case_pb2.CaseRequest(id=self.id)
def gridCount(self):
try:
return self.stub.GetGridCount(self.request).count
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.NOT_FOUND:
return 0
print("ERROR: ", e)
return 0
def grid(self, index):
return Grid(index, self)
def grids(self):
gridList = []
for i in range(0, self.gridCount()):
gridList.append(Grid(i, self))
return gridList
def cellCount(self, porosityModel='MATRIX_MODEL'):
porosityModelEnum = Case_pb2.PorosityModelType.Value(porosityModel)
request = Case_pb2.CellInfoRequest(request_case=self.request,
porosity_model=porosityModel)
return self.stub.GetCellCount(request)
def cellInfoForActiveCells(self, porosityModel='MATRIX_MODEL'):
porosityModelEnum = Case_pb2.PorosityModelType.Value(porosityModel)
request = Case_pb2.CellInfoRequest(request_case=self.request,
porosity_model=porosityModel)
return self.stub.GetCellInfoForActiveCells(request)
def timeSteps(self):
return self.stub.GetTimeSteps(self.request)

View File

@@ -0,0 +1,43 @@
import grpc
import os
import sys
import Commands_pb2 as Cmd
import Commands_pb2_grpc as CmdRpc
class Commands:
def __init__(self, channel):
self.commands = CmdRpc.CommandsStub(channel)
def execute(self, commandParams):
try:
return self.commands.Execute(commandParams)
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.NOT_FOUND:
print("Command not found")
else:
print("Other error")
def setTimeStep(self, caseId, timeStep):
return self.execute(Cmd.CommandParams(setTimeStep=Cmd.SetTimeStepParams(caseId=caseId, timeStep=timeStep)))
def setMainWindowSize(self, width, height):
return self.execute(Cmd.CommandParams(setMainWindowSize=Cmd.SetMainWindowSizeParams(width=width, height=height)))
def openProject(self, path):
return self.execute(Cmd.CommandParams(openProject=Cmd.FilePathRequest(path=path)))
def loadCase(self, path):
commandReply = self.execute(Cmd.CommandParams(loadCase=Cmd.FilePathRequest(path=path)))
assert commandReply.HasField("loadCaseResult")
return commandReply.loadCaseResult.id
def closeProject(self):
return self.execute(Cmd.CommandParams(closeProject=Empty()))
def exportWellPaths(self, wellPaths=[], mdStepSize=5.0):
if isinstance(wellPaths, str):
wellPathArray = [str]
elif isinstance(wellPaths, list):
wellPathArray = wellPaths
return self.execute(Cmd.CommandParams(exportWellPaths=Cmd.ExportWellPathRequest(wellPathNames=wellPathArray, mdStepSize=mdStepSize)))

View File

@@ -0,0 +1,18 @@
import grpc
import os
import sys
sys.path.insert(1, os.path.join(sys.path[0], '../generated'))
import Grid_pb2
import Grid_pb2_grpc
class Grid:
def __init__(self, index, case):
self.case = case
self.index = index
self.stub = Grid_pb2_grpc.GridStub(self.case.channel)
def dimensions(self):
return self.stub.GetDimensions(Grid_pb2.GridRequest(case_request = self.case.request, grid_index = self.index)).dimensions

View File

@@ -0,0 +1,78 @@
import grpc
import os
import sys
import socket
import logging
sys.path.insert(1, os.path.join(sys.path[0], '../generated'))
import RiaVersionInfo
from .AppInfo import AppInfo
from .Commands import Commands
from .Project import Project
class Instance:
@staticmethod
def is_port_in_use(port):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(0.2)
return s.connect_ex(('localhost', port)) == 0
@staticmethod
def launch():
port = 50051
portEnv = os.environ.get('RESINSIGHT_GRPC_PORT')
if portEnv:
port = int(portEnv)
resInsightExecutable = os.environ.get('RESINSIGHT_EXECUTABLE')
if resInsightExecutable is None:
print('Error: Could not launch any ResInsight instances because RESINSIGHT_EXECUTABLE is not set')
return None
while Instance.is_port_in_use(port):
port += 1
print('Port ' + str(port))
print('Trying to launch', resInsightExecutable)
pid = os.spawnl(os.P_NOWAIT, resInsightExecutable, " --grpcserver " + str(port))
print(pid)
return Instance(port)
@staticmethod
def find(startPort = 50051, endPort = 50071):
portEnv = os.environ.get('RESINSIGHT_GRPC_PORT')
if portEnv:
startPort = int(portEnv)
endPort = startPort + 20
for tryPort in range(startPort, endPort):
if Instance.is_port_in_use(tryPort):
return Instance(tryPort)
print('Error: Could not find any ResInsight instances responding between ports ' + str(startPort) + ' and ' + str(endPort))
return None
def __init__(self, port = 50051):
logging.basicConfig()
location = "localhost:" + str(port)
self.channel = grpc.insecure_channel(location)
# Main version check package
self.appInfo = AppInfo(self.channel)
try:
majorVersionOk = self.appInfo.majorVersion() == int(RiaVersionInfo.RESINSIGHT_MAJOR_VERSION)
minorVersionOk = self.appInfo.minorVersion() == int(RiaVersionInfo.RESINSIGHT_MINOR_VERSION)
if not (majorVersionOk and minorVersionOk):
raise Exception('Version of ResInsight does not match version of Python API')
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.UNAVAILABLE:
print('Info: Could not find any instances at port ' + str(port))
except Exception as e:
print('Error:', e)
# Service packages
self.commands = Commands(self.channel)
self.project = Project(self.channel)

View File

@@ -0,0 +1,45 @@
import grpc
import os
import sys
from .Case import Case
sys.path.insert(1, os.path.join(sys.path[0], '../generated'))
from Empty_pb2 import Empty
import Project_pb2
import Project_pb2_grpc
class Project:
def __init__(self, channel):
self.channel = channel
self.project = Project_pb2_grpc.ProjectStub(channel)
def selectedCases(self):
caseInfos = self.project.GetSelectedCases(Empty())
cases = []
for caseInfo in caseInfos.data:
cases.append(Case(self.channel, caseInfo.id))
return cases
def cases(self):
try:
caseInfos = self.project.GetAllCases(Empty())
cases = []
for caseInfo in caseInfos.data:
cases.append(Case(self.channel, caseInfo.id))
return cases
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.NOT_FOUND:
return []
else:
print("ERROR: ", e)
return []
def case(self, id):
try:
case = Case(self.channel, id)
return case
except grpc.RpcError as e:
return None

View File

@@ -0,0 +1,130 @@
import grpc
import os
import sys
sys.path.insert(1, os.path.join(sys.path[0], '../generated'))
import Properties_pb2
import Properties_pb2_grpc
import Case_pb2
import Case_pb2_grpc
class Properties:
def __init__(self, case):
self.case = case
self.propertiesStub = Properties_pb2_grpc.PropertiesStub(self.case.channel)
def generatePropertyInputIterator(self, values_iterator, parameters):
chunk = Properties_pb2.PropertyInputChunk()
chunk.params.CopyFrom(parameters)
yield chunk
for values in values_iterator:
valmsg = Properties_pb2.PropertyChunk(values = values)
chunk.values.CopyFrom(valmsg)
yield chunk
def generatePropertyInputChunks(self, array, parameters):
# Each double is 8 bytes. A good chunk size is 64KiB = 65536B
# Meaning ideal number of doubles would be 8192.
# However we need overhead space, so if we choose 8160 in chunk size
# We have 256B left for overhead which should be plenty
chunkSize = 8000
index = -1
while index < len(array):
chunk = Properties_pb2.PropertyInputChunk()
if index is -1:
chunk.params.CopyFrom(parameters)
index += 1;
else:
actualChunkSize = min(len(array) - index + 1, chunkSize)
chunk.values.CopyFrom(Properties_pb2.PropertyChunk(values = array[index:index+actualChunkSize]))
index += actualChunkSize
yield chunk
# Final empty message to signal completion
chunk = Properties_pb2.PropertyInputChunk()
yield chunk
def available(self, propertyType, porosityModel = 'MATRIX_MODEL'):
propertyTypeEnum = Properties_pb2.PropertyType.Value(propertyType)
porosityModelEnum = Case_pb2.PorosityModelType.Value(porosityModel)
request = Properties_pb2.AvailablePropertiesRequest (case_request = Case_pb2.CaseRequest(id=self.case.id),
property_type = propertyTypeEnum,
porosity_model = porosityModelEnum)
return self.propertiesStub.GetAvailableProperties(request).property_names
def activeCellProperty(self, propertyType, propertyName, timeStep, porosityModel = 'MATRIX_MODEL'):
propertyTypeEnum = Properties_pb2.PropertyType.Value(propertyType)
porosityModelEnum = Case_pb2.PorosityModelType.Value(porosityModel)
request = Properties_pb2.PropertyRequest(case_request = Case_pb2.CaseRequest(id=self.case.id),
property_type = propertyTypeEnum,
property_name = propertyName,
time_step = timeStep,
porosity_model = porosityModelEnum)
for chunk in self.propertiesStub.GetActiveCellProperty(request):
yield chunk
def gridProperty(self, propertyType, propertyName, timeStep, gridIndex = 0, porosityModel = 'MATRIX_MODEL'):
propertyTypeEnum = Properties_pb2.PropertyType.Value(propertyType)
porosityModelEnum = Case_pb2.PorosityModelType.Value(porosityModel)
request = Properties_pb2.PropertyRequest(case_request = self.case.request,
property_type = propertyTypeEnum,
property_name = propertyName,
time_step = timeStep,
grid_index = gridIndex,
porosity_model = porosityModelEnum)
return self.propertiesStub.GetGridProperty(request)
def setActiveCellPropertyAsync(self, values_iterator, propertyType, propertyName, timeStep, gridIndex = 0, porosityModel = 'MATRIX_MODEL'):
propertyTypeEnum = Properties_pb2.PropertyType.Value(propertyType)
porosityModelEnum = Case_pb2.PorosityModelType.Value(porosityModel)
request = Properties_pb2.PropertyRequest(case_request = self.case.request,
property_type = propertyTypeEnum,
property_name = propertyName,
time_step = timeStep,
grid_index = gridIndex,
porosity_model = porosityModelEnum)
try:
reply_iterator = self.generatePropertyInputIterator(values_iterator, request)
self.propertiesStub.SetActiveCellProperty(reply_iterator)
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.NOT_FOUND:
print("Command not found")
else:
print("Other error", e)
def setActiveCellProperty(self, values, propertyType, propertyName, timeStep, gridIndex = 0, porosityModel = 'MATRIX_MODEL'):
propertyTypeEnum = Properties_pb2.PropertyType.Value(propertyType)
porosityModelEnum = Case_pb2.PorosityModelType.Value(porosityModel)
request = Properties_pb2.PropertyRequest(case_request = self.case.request,
property_type = propertyTypeEnum,
property_name = propertyName,
time_step = timeStep,
grid_index = gridIndex,
porosity_model = porosityModelEnum)
try:
request_iterator = self.generatePropertyInputChunks(values, request)
self.propertiesStub.SetActiveCellProperty(request_iterator)
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.NOT_FOUND:
print("Command not found")
else:
print("Other error", e)
def setGridProperty(self, values, propertyType, propertyName, timeStep, gridIndex = 0, porosityModel = 'MATRIX_MODEL'):
propertyTypeEnum = Properties_pb2.PropertyType.Value(propertyType)
porosityModelEnum = Case_pb2.PorosityModelType.Value(porosityModel)
request = Properties_pb2.PropertyRequest(case_request = self.case.request,
property_type = propertyTypeEnum,
property_name = propertyName,
time_step = timeStep,
grid_index = gridIndex,
porosity_model = porosityModelEnum)
try:
request_iterator = self.generatePropertyInputChunks(values, request)
self.propertiesStub.SetGridProperty(request_iterator)
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.NOT_FOUND:
print("Command not found")
else:
print("Other error", e)

View File

@@ -0,0 +1,78 @@
import grpc
import os
import sys
import socket
import logging
sys.path.insert(1, os.path.join(sys.path[0], '../generated'))
import RiaVersionInfo
from AppInfo import AppInfo
from Commands import Commands
from Project import Project
class Instance:
@staticmethod
def is_port_in_use(port):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(0.2)
return s.connect_ex(('localhost', port)) == 0
@staticmethod
def launch():
port = 50051
portEnv = os.environ.get('RESINSIGHT_GRPC_PORT')
if portEnv:
port = int(portEnv)
resInsightExecutable = os.environ.get('RESINSIGHT_EXECUTABLE')
if resInsightExecutable is None:
print('Error: Could not launch any ResInsight instances because RESINSIGHT_EXECUTABLE is not set')
return None
while Instance.is_port_in_use(port):
port += 1
print('Port ' + str(port))
print('Trying to launch', resInsightExecutable)
pid = os.spawnl(os.P_NOWAIT, resInsightExecutable, " --grpcserver " + str(port))
print(pid)
return Instance(port)
@staticmethod
def find(startPort = 50051, endPort = 50071):
portEnv = os.environ.get('RESINSIGHT_GRPC_PORT')
if portEnv:
startPort = int(portEnv)
endPort = startPort + 20
for tryPort in range(startPort, endPort):
if Instance.is_port_in_use(tryPort):
return Instance(tryPort)
print('Error: Could not find any ResInsight instances responding between ports ' + str(startPort) + ' and ' + str(endPort))
return None
def __init__(self, port = 50051):
logging.basicConfig()
location = "localhost:" + str(port)
self.channel = grpc.insecure_channel(location)
# Main version check package
self.appInfo = AppInfo(self.channel)
try:
majorVersionOk = self.appInfo.majorVersion() == int(RiaVersionInfo.RESINSIGHT_MAJOR_VERSION)
minorVersionOk = self.appInfo.minorVersion() == int(RiaVersionInfo.RESINSIGHT_MINOR_VERSION)
if not (majorVersionOk and minorVersionOk):
raise Exception('Version of ResInsight does not match version of Python API')
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.UNAVAILABLE:
print('Info: Could not find any instances at port ' + str(port))
except Exception as e:
print('Error:', e)
# Service packages
self.commands = Commands(self.channel)
self.project = Project(self.channel)

View File

@@ -0,0 +1,5 @@
name = "rips"
from .Case import Case
from .Grid import Grid
from .Properties import Properties
from .Instance import Instance

View File

@@ -0,0 +1,21 @@
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=find_packages(exclude=('tests', 'docs', '__pycache', 'examples'))
)