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

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']
)