mirror of
https://github.com/OPM/ResInsight.git
synced 2026-08-27 05:37:21 -05:00
591 lines
16 KiB
Python
591 lines
16 KiB
Python
# pylint: disable=too-many-arguments
|
|
# pylint: disable=no-member
|
|
"""
|
|
The ResInsight project module
|
|
"""
|
|
|
|
import grpc
|
|
import uuid
|
|
|
|
from .case import Case
|
|
from .gridcasegroup import GridCaseGroup
|
|
from .pdmobject import add_method, add_static_method
|
|
from .plot import Plot as Plot
|
|
from .view import View
|
|
|
|
import Commands_pb2
|
|
from Definitions_pb2 import Empty
|
|
import Project_pb2_grpc
|
|
import KeyValueStore_pb2_grpc
|
|
import KeyValueStore_pb2
|
|
|
|
from .resinsight_classes import (
|
|
ColorLegendCollection,
|
|
PlotWindow,
|
|
Project,
|
|
Reservoir,
|
|
SummaryCase,
|
|
WellPath,
|
|
)
|
|
|
|
from typing import Optional, List
|
|
|
|
|
|
@add_method(Project)
|
|
def __custom_init__(self, pb2_object, channel: grpc.Channel) -> None:
|
|
self._project_stub = Project_pb2_grpc.ProjectStub(self._channel)
|
|
self.__key_value_store_stub = KeyValueStore_pb2_grpc.KeyValueStoreStub(
|
|
self._channel
|
|
)
|
|
|
|
# Public properties
|
|
self.chunk_size = 8160
|
|
|
|
|
|
@add_static_method(Project)
|
|
def create(channel: grpc.Channel) -> Project:
|
|
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) -> None:
|
|
"""Close the current project (and open new blank project)"""
|
|
self._execute_command(closeProject=Empty())
|
|
|
|
|
|
@add_method(Project)
|
|
def load_case(self: Project, path: str, grid_only: bool = False) -> Reservoir:
|
|
"""Load a new grid case from the given file path
|
|
|
|
Arguments:
|
|
path(str): file path to case
|
|
Returns:
|
|
:class:`rips.generated.generated_classes.Case`
|
|
"""
|
|
command_reply = self._execute_command(
|
|
loadCase=Commands_pb2.FilePathRequest(path=path, gridOnly=grid_only)
|
|
)
|
|
return self.case(command_reply.loadCaseResult.id)
|
|
|
|
|
|
@add_method(Project)
|
|
def selected_cases(self) -> List[Case]:
|
|
"""Get a list of all grid cases selected in the project tree
|
|
|
|
Returns:
|
|
A list of :class:`rips.generated.generated_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: Project) -> List[Reservoir]:
|
|
"""Get a list of all grid cases in the project
|
|
|
|
Returns:
|
|
A list of :class:`rips.generated.generated_classes.Case`
|
|
"""
|
|
return self.descendants(Reservoir)
|
|
|
|
|
|
@add_method(Project)
|
|
def case(self: Project, case_id: int) -> Optional[Reservoir]:
|
|
"""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 color_legend_collection(self: Project) -> Optional[ColorLegendCollection]:
|
|
"""Get the project's color legend collection
|
|
|
|
Returns:
|
|
:class:`rips.generated.generated_classes.ColorLegendCollection`
|
|
"""
|
|
collections = self.descendants(ColorLegendCollection)
|
|
return collections[0] if collections else None
|
|
|
|
|
|
@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.generated_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.generated_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.generated_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.generated_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.generated_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", width=-1, height=-1
|
|
):
|
|
"""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,
|
|
width=width,
|
|
height=height,
|
|
)
|
|
)
|
|
|
|
|
|
@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.generated_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.generated_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.generated_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
|
|
)
|
|
)
|
|
|
|
|
|
@add_method(Project)
|
|
def create_corner_point_grid(
|
|
self,
|
|
name: str,
|
|
nx: int,
|
|
ny: int,
|
|
nz: int,
|
|
coord: List[float],
|
|
zcorn: List[float],
|
|
actnum: List[int],
|
|
):
|
|
"""Creates a corner point grid from given parameters.
|
|
|
|
Arguments:
|
|
name(str): Name of the grid.
|
|
nx(int): Number of cells in x direction
|
|
ny(int): Number of cells in y direction
|
|
nz(int): Number of cells in z direction
|
|
coord(list[float]): Coordinate lines as COORD keyword in Eclipse.
|
|
Each coordinate line is defined by two points (top and bottom).
|
|
Size: (nx+1) * (ny+1) * 2 * 3. Points are ordered as in Eclipse.
|
|
zcorn(list[float]): Corner depths as defined by the Eclipse keyword ZCORN.
|
|
Size: nx * ny * nz * 8
|
|
actnum(list[int]): Active cell info: cells with values > 0 are active.
|
|
Size: nx * ny * nz
|
|
"""
|
|
|
|
# Generate unique keys for three arrays
|
|
coord_key = "{}_{}".format(uuid.uuid4(), "coord")
|
|
zcorn_key = "{}_{}".format(uuid.uuid4(), "zcorn")
|
|
actnum_key = "{}_{}".format(uuid.uuid4(), "actnum")
|
|
|
|
self.set_key_values(coord_key, coord)
|
|
self.set_key_values(zcorn_key, zcorn)
|
|
self.set_key_values(actnum_key, actnum)
|
|
return self.create_grid_from_key_values(
|
|
name=name,
|
|
nx=nx,
|
|
ny=ny,
|
|
nz=nz,
|
|
coord_key=coord_key,
|
|
zcorn_key=zcorn_key,
|
|
actnum_key=actnum_key,
|
|
)
|
|
|
|
|
|
@add_method(Project)
|
|
def set_key_values(self, key, values):
|
|
"""Sets values for a given key in the key-value store.
|
|
|
|
Arguments:
|
|
key(str): The key (should be unique).
|
|
values(list): a list of double precision floating point numbers
|
|
"""
|
|
request_iterator = self.__generate_key_value_store_input_chunks(values, key)
|
|
reply = self.__key_value_store_stub.SetValue(request_iterator)
|
|
if reply.accepted_value_count < len(values):
|
|
raise IndexError
|
|
|
|
|
|
@add_method(Project)
|
|
def __generate_key_value_store_input_chunks(self, array, name):
|
|
index = -1
|
|
while index < len(array):
|
|
chunk = KeyValueStore_pb2.KeyValueStoreInputChunk()
|
|
if index == -1:
|
|
parameters = KeyValueStore_pb2.KeyValueInputParameters(
|
|
name=name, num_elements=len(array)
|
|
)
|
|
chunk.parameters.CopyFrom(parameters)
|
|
index += 1
|
|
else:
|
|
actual_chunk_size = min(len(array) - index + 1, self.chunk_size)
|
|
chunk.values.CopyFrom(
|
|
KeyValueStore_pb2.KeyValueStoreChunk(
|
|
values=array[index : index + actual_chunk_size]
|
|
)
|
|
)
|
|
index += actual_chunk_size
|
|
|
|
yield chunk
|
|
# Final empty message to signal completion
|
|
chunk = KeyValueStore_pb2.KeyValueStoreInputChunk()
|
|
yield chunk
|
|
|
|
|
|
@add_method(Project)
|
|
def key_values_async(
|
|
self,
|
|
key,
|
|
):
|
|
"""Get float values for a given key. Async: returns an iterator.
|
|
|
|
Arguments:
|
|
key(str): The key to get.
|
|
|
|
Returns:
|
|
An iterator to a chunk object containing an array of float values
|
|
Loop through the chunks and then the values within the chunk to get all values.
|
|
"""
|
|
request = KeyValueStore_pb2.KeyValueStoreOutputRequest(name=key)
|
|
for chunk in self.__key_value_store_stub.GetValue(request):
|
|
yield chunk
|
|
|
|
|
|
@add_method(Project)
|
|
def key_values(self, key):
|
|
"""Get float values for a given key. Synchronous: returns a list. `
|
|
|
|
Arguments:
|
|
key(str): The key to get.
|
|
|
|
Returns:
|
|
A list of float values
|
|
"""
|
|
all_values = []
|
|
generator = self.key_values_async(key)
|
|
for chunk in generator:
|
|
for value in chunk.values:
|
|
all_values.append(value)
|
|
return all_values
|
|
|
|
|
|
@add_method(Project)
|
|
def remove_key_values(self, key):
|
|
"""Remove the values for a given key in the key-value store.
|
|
|
|
Arguments:
|
|
key(str): The key.
|
|
"""
|
|
request = KeyValueStore_pb2.KeyValueStoreRemoveRequest(name=key)
|
|
self.__key_value_store_stub.RemoveValue(request)
|