mirror of
https://github.com/OPM/ResInsight.git
synced 2026-11-01 16:43:03 -06:00
RimEclipseResultCase_exportFlowCharacteristics has the same arguments as the legacy command (lists only, no scalar shorthand). RicfExportFlowCharacteristics forwards to it. The hand-written Case.export_flow_characteristics() Python wrapper is removed: the generated EclipseCase method has the same name and argument names and shadows it for all cases the command applies to.
1509 lines
51 KiB
Python
1509 lines
51 KiB
Python
# pylint: disable=no-member
|
|
# pylint: disable=too-many-arguments
|
|
# pylint: disable=too-many-public-methods
|
|
# pylint: disable=no-self-use
|
|
|
|
"""
|
|
Module containing the Case class
|
|
|
|
ResInsight Case class
|
|
|
|
Operate on a ResInsight case specified by a Case Id integer.
|
|
Not meant to be constructed separately but created by one of the following
|
|
methods in Project: loadCase, case, allCases, selectedCases
|
|
|
|
.. _result-definition-label:
|
|
|
|
Result Definition
|
|
-----------------
|
|
When working with grid case results, the following two arguments are used in many functions to identify a
|
|
result
|
|
|
|
**Result Definition enums**::
|
|
|
|
property_type | | porosity_model
|
|
(str enum) | | (str enum)
|
|
----------------------- | ----- | --------------
|
|
DYNAMIC_NATIVE | | MATRIX_MODEL
|
|
STATIC_NATIVE | | FRACTURE_MODEL
|
|
SOURSIMRL | |
|
|
GENERATED | |
|
|
INPUT_PROPERTY | |
|
|
FORMATION_NAMES | |
|
|
FLOW_DIAGNOSTICS | |
|
|
INJECTION_FLOODING | |
|
|
|
|
"""
|
|
|
|
import grpc
|
|
import uuid
|
|
import warnings
|
|
from typing import Any, Iterable, Iterator, List, Optional, Tuple, Union
|
|
|
|
import Case_pb2
|
|
import Case_pb2_grpc
|
|
import Commands_pb2 as Cmd
|
|
import PdmObject_pb2 as PdmObject_pb2
|
|
import Definitions_pb2
|
|
|
|
import Properties_pb2
|
|
import Properties_pb2_grpc
|
|
import NNCProperties_pb2
|
|
import NNCProperties_pb2_grpc
|
|
from .resinsight_classes import (
|
|
Case as Case,
|
|
EclipseCase as EclipseCase,
|
|
GeoMechCase as GeoMechCase,
|
|
PorosityModelType as PorosityModelType,
|
|
PropertyDataType as PropertyDataType,
|
|
PropertyType as PropertyType,
|
|
Reservoir as Reservoir,
|
|
WellBoreStabilityPlot as WellBoreStabilityPlot,
|
|
WbsParameters as WbsParameters,
|
|
)
|
|
|
|
from .exception import RipsError
|
|
from .grid import Grid as Grid
|
|
from .project import Project as Project
|
|
from .pdmobject import add_method
|
|
from .view import View as View
|
|
from .simulation_well import SimulationWell
|
|
import rips.project # full name import due to circular dependency
|
|
|
|
|
|
@add_method(Case)
|
|
def __custom_init__(
|
|
self, pb2_object: PdmObject_pb2.PdmObject, channel: grpc.Channel
|
|
) -> None:
|
|
self.__case_stub = Case_pb2_grpc.CaseStub(self._channel)
|
|
|
|
self.__properties_stub = Properties_pb2_grpc.PropertiesStub(self._channel)
|
|
self.__nnc_properties_stub = NNCProperties_pb2_grpc.NNCPropertiesStub(self._channel)
|
|
|
|
# Public properties
|
|
self.chunk_size = 8160
|
|
|
|
|
|
@add_method(Case)
|
|
def __grid_count(self) -> int:
|
|
"""Get number of grids in the case"""
|
|
try:
|
|
return self.__case_stub.GetGridCount(self.__request()).count
|
|
except grpc.RpcError as exception:
|
|
if exception.code() == grpc.StatusCode.NOT_FOUND:
|
|
return 0
|
|
raise RipsError.from_rpc_error(exception) from exception
|
|
|
|
|
|
@add_method(Case)
|
|
def __request(self) -> Case_pb2.CaseRequest:
|
|
return Case_pb2.CaseRequest(id=self.id)
|
|
|
|
|
|
@add_method(Case)
|
|
def __generate_property_input_iterator(
|
|
self,
|
|
values_iterator: Iterable[List[float]],
|
|
parameters: Properties_pb2.PropertyRequest,
|
|
) -> Iterator[Properties_pb2.PropertyInputChunk]:
|
|
chunk = Properties_pb2.PropertyInputChunk()
|
|
chunk.params.CopyFrom(parameters)
|
|
yield chunk
|
|
|
|
for values in values_iterator:
|
|
valmsg = Properties_pb2.PropertyChunk(values=values)
|
|
chunk.values.CopyFrom(valmsg)
|
|
yield chunk
|
|
|
|
|
|
@add_method(Case)
|
|
def __generate_property_input_chunks(
|
|
self, array: List[float], parameters: Properties_pb2.PropertyRequest
|
|
) -> Iterator[Properties_pb2.PropertyInputChunk]:
|
|
index = -1
|
|
while index < len(array):
|
|
chunk = Properties_pb2.PropertyInputChunk()
|
|
if index == -1:
|
|
chunk.params.CopyFrom(parameters)
|
|
index += 1
|
|
else:
|
|
actual_chunk_size = min(len(array) - index + 1, self.chunk_size)
|
|
chunk.values.CopyFrom(
|
|
Properties_pb2.PropertyChunk(
|
|
values=array[index : index + actual_chunk_size]
|
|
)
|
|
)
|
|
index += actual_chunk_size
|
|
|
|
yield chunk
|
|
# Final empty message to signal completion
|
|
chunk = Properties_pb2.PropertyInputChunk()
|
|
yield chunk
|
|
|
|
|
|
@add_method(Case)
|
|
def grid(self, index: int = 0) -> Grid:
|
|
"""Get Grid of a given index
|
|
|
|
Arguments:
|
|
index (int): The grid index
|
|
|
|
Returns:
|
|
:class:`rips.grid.Grid`
|
|
"""
|
|
return Grid(index, self, self.channel())
|
|
|
|
|
|
@add_method(Case)
|
|
def grids(self) -> List[Grid]:
|
|
"""Get a list of all rips Grid objects in the case
|
|
|
|
Returns:
|
|
List of :class:`rips.grid.Grid`
|
|
"""
|
|
grid_list = []
|
|
for i in range(0, self.__grid_count()):
|
|
grid_list.append(Grid(i, self, self.channel()))
|
|
return grid_list
|
|
|
|
|
|
@add_method(Case)
|
|
def replace(self, new_grid_file: str) -> None:
|
|
"""Replace the current case grid with a new grid loaded from file
|
|
|
|
Deprecated: use replace_grid(new_grid_file) instead.
|
|
|
|
Arguments:
|
|
new_grid_file (str): Path to EGRID file
|
|
"""
|
|
warnings.warn(
|
|
"Case.replace() is deprecated, use Case.replace_grid() instead",
|
|
DeprecationWarning,
|
|
stacklevel=3,
|
|
)
|
|
project = self.ancestor(rips.project.Project)
|
|
self.replace_grid(new_grid_file=new_grid_file)
|
|
new_case = project.case(self.id)
|
|
self.copy_from(new_case)
|
|
|
|
|
|
@add_method(Case)
|
|
def cell_count(
|
|
self, porosity_model: PorosityModelType = PorosityModelType.MATRIX_MODEL
|
|
) -> Case_pb2.CellCount:
|
|
"""Get a cell count object containing number of active cells and total number of cells
|
|
|
|
Arguments:
|
|
porosity_model (str): String representing an enum.
|
|
must be 'MATRIX_MODEL' or 'FRACTURE_MODEL'.
|
|
Returns:
|
|
Cell Count object with the following integer attributes:
|
|
active_cell_count: number of active cells
|
|
reservoir_cell_count: total number of reservoir cells
|
|
|
|
**CellCount class description**::
|
|
|
|
Parameter | Description | Type
|
|
----------------------- | ------------------------- | -----
|
|
active_cell_count | Number of active cells | Integer
|
|
reservoir_cell_count | Total number of cells | Integer
|
|
|
|
"""
|
|
porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model)
|
|
request = Case_pb2.CellInfoRequest(
|
|
case_request=self.__request(), porosity_model=porosity_model_enum
|
|
)
|
|
return self.__case_stub.GetCellCount(request)
|
|
|
|
|
|
@add_method(Case)
|
|
def cell_info_for_active_cells_async(
|
|
self, porosity_model: PorosityModelType = PorosityModelType.MATRIX_MODEL
|
|
) -> Iterator[Case_pb2.CellInfoArray]:
|
|
"""Get Stream of cell info objects for current case
|
|
|
|
Arguments:
|
|
porosity_model(str): String representing an enum.
|
|
must be 'MATRIX_MODEL' or 'FRACTURE_MODEL'.
|
|
|
|
Returns:
|
|
Stream of **CellInfo** objects
|
|
|
|
See :meth:`rips.case.cell_info_for_active_cells()` for detalis on the **CellInfo** class.
|
|
"""
|
|
porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model)
|
|
request = Case_pb2.CellInfoRequest(
|
|
case_request=self.__request(), porosity_model=porosity_model_enum
|
|
)
|
|
return self.__case_stub.GetCellInfoForActiveCells(request)
|
|
|
|
|
|
@add_method(Case)
|
|
def cell_info_for_active_cells(
|
|
self, porosity_model: PorosityModelType = PorosityModelType.MATRIX_MODEL
|
|
) -> List[Case_pb2.CellInfo]:
|
|
"""Get list of cell info objects for current case
|
|
|
|
Arguments:
|
|
porosity_model(str): String representing an enum.
|
|
must be 'MATRIX_MODEL' or 'FRACTURE_MODEL'.
|
|
|
|
Returns:
|
|
List of **CellInfo** objects
|
|
|
|
**CellInfo class description**::
|
|
|
|
Parameter | Description | Type
|
|
------------------------- | --------------------------------------------- | -----
|
|
grid_index | Index to grid | Integer
|
|
parent_grid_index | Index to parent grid | Integer
|
|
coarsening_box_index | Index to coarsening box | Integer
|
|
local_ijk | Cell index in IJK directions of local grid | Vec3i
|
|
parent_ijk | Cell index in IJK directions of parent grid | Vec3i
|
|
|
|
**Vec3i class description**::
|
|
|
|
Parameter | Description | Type
|
|
---------------- | -------------------------------------------- | -----
|
|
i | I grid index | Integer
|
|
j | J grid index | Integer
|
|
k | K grid index | Integer
|
|
|
|
"""
|
|
active_cell_info_chunks = self.cell_info_for_active_cells_async(
|
|
porosity_model=porosity_model
|
|
)
|
|
received_active_cells = []
|
|
for active_cell_chunk in active_cell_info_chunks:
|
|
for active_cell in active_cell_chunk.data:
|
|
received_active_cells.append(active_cell)
|
|
return received_active_cells
|
|
|
|
|
|
@add_method(Case)
|
|
def time_steps(self) -> List[Case_pb2.TimeStepDate]:
|
|
"""Get a list containing all time steps
|
|
|
|
The time steps are defined by the class **TimeStepDate**
|
|
|
|
**TimeStepDate class description**::
|
|
|
|
Type | Name
|
|
--------- | ----------
|
|
int | year
|
|
int | month
|
|
int | day
|
|
int | hour
|
|
int | minute
|
|
int | second
|
|
|
|
|
|
"""
|
|
return self.__case_stub.GetTimeSteps(self.__request()).dates
|
|
|
|
|
|
@add_method(Case)
|
|
def reservoir_boundingbox(self) -> Case_pb2.BoundingBox:
|
|
"""Get the reservoir bounding box
|
|
|
|
Returns:
|
|
BoundingBox
|
|
|
|
**BoundingBox class description**::
|
|
|
|
Type | Name
|
|
--------- | ----------
|
|
int | min_x
|
|
int | max_x
|
|
int | min_y
|
|
int | max_y
|
|
int | min_z
|
|
int | max_z
|
|
|
|
|
|
"""
|
|
return self.__case_stub.GetReservoirBoundingBox(self.__request())
|
|
|
|
|
|
@add_method(Case)
|
|
def distance_to_closest_fault(
|
|
self, x: float, y: float, z: float
|
|
) -> Tuple[str, float, str]:
|
|
"""Find the closest fault to the given point and return the distance, fault name and fault face"""
|
|
request = Case_pb2.ClosestFaultRequest(
|
|
case_request=self.__request(), point=Definitions_pb2.Vec3d(x=x, y=y, z=z)
|
|
)
|
|
reply = self.__case_stub.GetDistanceToClosestFault(request)
|
|
|
|
return (reply.fault_name, reply.distance, reply.face_name)
|
|
|
|
|
|
@add_method(Case)
|
|
def reservoir_depth_range(self) -> Tuple[float, float]:
|
|
"""Get the reservoir depth range
|
|
|
|
Returns:
|
|
A tuple with two members. The first is the minimum depth, the second is the maximum depth
|
|
"""
|
|
bbox = self.reservoir_boundingbox()
|
|
return -bbox.max_z, -bbox.min_z
|
|
|
|
|
|
@add_method(Case)
|
|
def days_since_start(self) -> List[float]:
|
|
"""Get a list of decimal values representing days since the start of the simulation"""
|
|
return self.__case_stub.GetDaysSinceStart(self.__request()).day_decimals
|
|
|
|
|
|
@add_method(Case)
|
|
def view(self, view_id: int) -> Optional[View]:
|
|
"""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`
|
|
"""
|
|
project = self.ancestor(rips.project.Project)
|
|
views = project.views()
|
|
for view_object in views:
|
|
if view_object.id == view_id:
|
|
return view_object
|
|
return None
|
|
|
|
|
|
@add_method(Case)
|
|
def views(self) -> List[View]:
|
|
"""Get all views of a case
|
|
|
|
Returns:
|
|
List of :class:`rips.generated.generated_classes.View`
|
|
"""
|
|
project = self.ancestor(rips.project.Project)
|
|
views = project.views()
|
|
views_for_case = []
|
|
for view_object in views:
|
|
view_case = view_object.case()
|
|
if view_case is not None and view_case.id == self.id:
|
|
views_for_case.append(view_object)
|
|
return views_for_case
|
|
|
|
|
|
@add_method(Case)
|
|
def export_snapshots_of_all_views(
|
|
self, prefix: str = "", export_folder: str = ""
|
|
) -> None:
|
|
"""Export snapshots for all views in the case
|
|
|
|
Deprecated: loop over views() and call View.export_snapshot() instead.
|
|
|
|
Arguments:
|
|
prefix (str): Exported file name prefix
|
|
export_folder(str): The path to export to. By default will use the 'snapshots' folder next to the project file.
|
|
|
|
"""
|
|
warnings.warn(
|
|
"Case.export_snapshots_of_all_views() is deprecated, use View.export_snapshot() on each view instead",
|
|
DeprecationWarning,
|
|
stacklevel=3,
|
|
)
|
|
for view in self.views():
|
|
view.export_snapshot(export_folder=export_folder, prefix=prefix)
|
|
|
|
|
|
@add_method(Case)
|
|
def export_well_path_completions(
|
|
self,
|
|
time_step: int,
|
|
well_path_names: Union[str, List[str]],
|
|
file_split: str,
|
|
compdat_export: str = "TRANSMISSIBILITIES",
|
|
include_perforations: bool = True,
|
|
include_fishbones: bool = True,
|
|
fishbones_exclude_main_bore: bool = True,
|
|
export_welspec: bool = True,
|
|
export_comments: bool = True,
|
|
custom_file_name: str = "",
|
|
) -> Any:
|
|
"""
|
|
Export well path completions for the current case to file
|
|
|
|
**Parameters**::
|
|
|
|
Parameter | Description | Type
|
|
----------------------------| ------------------------------------------------ | -----
|
|
time_step | Time step to export for | Integer
|
|
well_path_names | List of well path names | List
|
|
file_split | Controls how export data is split into files | String enum
|
|
compdat_export | Compdat export type | String enum
|
|
include_perforations | Export perforations? | bool
|
|
include_fishbones | Export fishbones? | bool
|
|
fishbones_exclude_main_bore | Exclude main bore when exporting fishbones? | bool
|
|
export_welspec | Export WELSPEC keyword | bool
|
|
export_comments | Export completion data source as comment | bool
|
|
custom_file_name | Custom filename when file_split is "UNIFIED_FILE"| String
|
|
|
|
**Enum file_split**::
|
|
|
|
Option | Description
|
|
----------------------------------- | ------------
|
|
"UNIFIED_FILE" | A single file with all combined transmissibilities
|
|
"SPLIT_ON_WELL" | One file for each well with combined transmissibilities
|
|
|
|
**Enum compdat_export**::
|
|
|
|
Option | Description
|
|
------------------------------------------- | ------------
|
|
"TRANSMISSIBILITIES" | Direct export of transmissibilities
|
|
"WPIMULT_AND_DEFAULT_CONNECTION_FACTORS" | Include WPIMULT in addition to transmissibilities
|
|
|
|
Deprecated: use Reservoir.export_completions(well_paths=[...], export_folder=...) instead,
|
|
which takes WellPath objects and an explicit export folder.
|
|
"""
|
|
warnings.warn(
|
|
"Case.export_well_path_completions() is deprecated, use Reservoir.export_completions() instead",
|
|
DeprecationWarning,
|
|
stacklevel=3,
|
|
)
|
|
if isinstance(well_path_names, str):
|
|
well_path_names = [well_path_names]
|
|
return self._execute_command(
|
|
exportWellPathCompletions=Cmd.ExportWellPathCompRequest(
|
|
caseId=self.id,
|
|
timeStep=time_step,
|
|
wellPathNames=well_path_names,
|
|
fileSplit=file_split,
|
|
compdatExport=compdat_export,
|
|
includePerforations=include_perforations,
|
|
includeFishbones=include_fishbones,
|
|
excludeMainBoreForFishbones=fishbones_exclude_main_bore,
|
|
exportWelspec=export_welspec,
|
|
exportComments=export_comments,
|
|
customFileName=custom_file_name,
|
|
)
|
|
)
|
|
|
|
|
|
@add_method(Case)
|
|
def export_msw(self, well_path: str) -> Any:
|
|
"""
|
|
Export Eclipse Multi-segment-well model to file
|
|
|
|
Deprecated: use Reservoir.export_msw_completions(well_paths=[...], export_folder=...) instead,
|
|
which takes WellPath objects and an explicit export folder.
|
|
|
|
Arguments:
|
|
well_path(str): Well path name
|
|
"""
|
|
warnings.warn(
|
|
"Case.export_msw() is deprecated, use Reservoir.export_msw_completions() instead",
|
|
DeprecationWarning,
|
|
stacklevel=3,
|
|
)
|
|
return self._execute_command(
|
|
exportMsw=Cmd.ExportMswRequest(caseId=self.id, wellPath=well_path)
|
|
)
|
|
|
|
|
|
@add_method(Case)
|
|
def create_lgr_for_completion(
|
|
self,
|
|
time_step: int,
|
|
well_path_names: Union[str, List[str]],
|
|
refinement_i: int,
|
|
refinement_j: int,
|
|
refinement_k: int,
|
|
split_type: str,
|
|
) -> Any:
|
|
"""
|
|
Create a local grid refinement for the completions on the given well paths
|
|
|
|
**Parameters**::
|
|
|
|
Parameter | Description | Type
|
|
--------------- | -------------------------------------- | -----
|
|
time_steps | Time step index | Integer
|
|
well_path_names | List of well path names | List of Strings
|
|
refinement_i | Refinement in x-direction | Integer
|
|
refinement_j | Refinement in y-direction | Integer
|
|
refinement_k | Refinement in z-direction | Integer
|
|
split_type | Defines how to split LGRS | String enum
|
|
|
|
**Enum split_type**::
|
|
|
|
Option | Description
|
|
------------------------| ------------
|
|
"LGR_PER_CELL" | One LGR for each completed cell
|
|
"LGR_PER_COMPLETION" | One LGR for each completion (fracture, perforation, ...)
|
|
"LGR_PER_WELL" | One LGR for each well
|
|
|
|
Deprecated: use Reservoir.create_lgr_for_completions(well_paths=[...], ...) instead, which takes
|
|
WellPath objects.
|
|
"""
|
|
warnings.warn(
|
|
"Case.create_lgr_for_completion() is deprecated, use Reservoir.create_lgr_for_completions() instead",
|
|
DeprecationWarning,
|
|
stacklevel=3,
|
|
)
|
|
if isinstance(well_path_names, str):
|
|
well_path_names = [well_path_names]
|
|
return self._execute_command(
|
|
createLgrForCompletions=Cmd.CreateLgrForCompRequest(
|
|
caseId=self.id,
|
|
timeStep=time_step,
|
|
wellPathNames=well_path_names,
|
|
refinementI=refinement_i,
|
|
refinementJ=refinement_j,
|
|
refinementK=refinement_k,
|
|
splitType=split_type,
|
|
)
|
|
)
|
|
|
|
|
|
@add_method(Case)
|
|
def create_saturation_pressure_plots(self) -> Any:
|
|
"""
|
|
Create saturation pressure plots for the current case
|
|
"""
|
|
case_ids = [self.id]
|
|
return self._execute_command(
|
|
createSaturationPressurePlots=Cmd.CreateSatPressPlotRequest(caseIds=case_ids)
|
|
)
|
|
|
|
|
|
@add_method(Case)
|
|
def available_properties(
|
|
self,
|
|
property_type: PropertyType,
|
|
porosity_model: PorosityModelType = PorosityModelType.MATRIX_MODEL,
|
|
) -> List[str]:
|
|
"""Get a list of available properties
|
|
|
|
For argument details, see :ref:`Result Definition <result-definition-label>`
|
|
|
|
Arguments:
|
|
property_type (str): string corresponding to property_type enum.
|
|
porosity_model(str): 'MATRIX_MODEL' or 'FRACTURE_MODEL'.
|
|
"""
|
|
|
|
property_type_enum = Properties_pb2.PropertyType.Value(property_type)
|
|
porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model)
|
|
request = Properties_pb2.AvailablePropertiesRequest(
|
|
case_request=self.__request(),
|
|
property_type=property_type_enum,
|
|
porosity_model=porosity_model_enum,
|
|
)
|
|
return self.__properties_stub.GetAvailableProperties(request).property_names
|
|
|
|
|
|
@add_method(Case)
|
|
def active_cell_property_async(
|
|
self,
|
|
property_type: PropertyType,
|
|
property_name: str,
|
|
time_step: int,
|
|
porosity_model: PorosityModelType = PorosityModelType.MATRIX_MODEL,
|
|
) -> Iterator[Properties_pb2.PropertyChunk]:
|
|
"""Get a cell property for all active cells. Async, so returns an iterator. For argument details, see :ref:`Result Definition <result-definition-label>`
|
|
|
|
Arguments:
|
|
property_type(str): string enum
|
|
property_name(str): name of an Eclipse property
|
|
time_step(int): the time step for which to get the property for
|
|
porosity_model(str): string enum
|
|
|
|
Returns:
|
|
An iterator to a chunk object containing an array of double values
|
|
Loop through the chunks and then the values within the chunk to get all values.
|
|
"""
|
|
property_type_enum = Properties_pb2.PropertyType.Value(property_type)
|
|
porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model)
|
|
request = Properties_pb2.PropertyRequest(
|
|
case_request=self.__request(),
|
|
property_type=property_type_enum,
|
|
property_name=property_name,
|
|
time_step=time_step,
|
|
porosity_model=porosity_model_enum,
|
|
)
|
|
for chunk in self.__properties_stub.GetActiveCellProperty(request):
|
|
yield chunk
|
|
|
|
|
|
@add_method(Case)
|
|
def active_cell_property(
|
|
self,
|
|
property_type: PropertyType,
|
|
property_name: str,
|
|
time_step: int,
|
|
porosity_model: PorosityModelType = PorosityModelType.MATRIX_MODEL,
|
|
) -> List[float]:
|
|
"""Get a cell property for all active cells. Sync, so returns a list. For argument details, see :ref:`Result Definition <result-definition-label>`
|
|
|
|
Arguments:
|
|
property_type(str): string enum
|
|
property_name(str): name of an Eclipse property
|
|
time_step(int): the time step for which to get the property for
|
|
porosity_model(str): string enum
|
|
|
|
Returns:
|
|
A list containing double values
|
|
Loop through the chunks and then the values within the chunk to get all values.
|
|
"""
|
|
all_values = []
|
|
generator = self.active_cell_property_async(
|
|
property_type, property_name, time_step, porosity_model
|
|
)
|
|
for chunk in generator:
|
|
for value in chunk.values:
|
|
all_values.append(value)
|
|
return all_values
|
|
|
|
|
|
@add_method(Case)
|
|
def selected_cell_property_async(
|
|
self,
|
|
property_type: PropertyType,
|
|
property_name: str,
|
|
time_step: int,
|
|
porosity_model: PorosityModelType = PorosityModelType.MATRIX_MODEL,
|
|
) -> Iterator[Properties_pb2.PropertyChunk]:
|
|
"""Get a cell property for all selected cells. Async, so returns an iterator. For argument details, see :ref:`Result Definition <result-definition-label>`
|
|
|
|
Arguments:
|
|
property_type(str): string enum
|
|
property_name(str): name of an Eclipse property
|
|
time_step(int): the time step for which to get the property for
|
|
porosity_model(str): string enum
|
|
|
|
Returns:
|
|
An iterator to a chunk object containing an array of double values
|
|
Loop through the chunks and then the values within the chunk to get all values.
|
|
"""
|
|
property_type_enum = Properties_pb2.PropertyType.Value(property_type)
|
|
porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model)
|
|
request = Properties_pb2.PropertyRequest(
|
|
case_request=self.__request(),
|
|
property_type=property_type_enum,
|
|
property_name=property_name,
|
|
time_step=time_step,
|
|
porosity_model=porosity_model_enum,
|
|
)
|
|
for chunk in self.__properties_stub.GetSelectedCellProperty(request):
|
|
yield chunk
|
|
|
|
|
|
@add_method(Case)
|
|
def selected_cell_property(
|
|
self,
|
|
property_type: PropertyType,
|
|
property_name: str,
|
|
time_step: int,
|
|
porosity_model: PorosityModelType = PorosityModelType.MATRIX_MODEL,
|
|
) -> List[float]:
|
|
"""Get a cell property for all selected cells. Sync, so returns a list. For argument details, see :ref:`Result Definition <result-definition-label>`
|
|
|
|
Arguments:
|
|
property_type(str): string enum
|
|
property_name(str): name of an Eclipse property
|
|
time_step(int): the time step for which to get the property for
|
|
porosity_model(str): string enum
|
|
|
|
Returns:
|
|
A list containing double values
|
|
Loop through the chunks and then the values within the chunk to get all values.
|
|
"""
|
|
all_values = []
|
|
generator = self.selected_cell_property_async(
|
|
property_type, property_name, time_step, porosity_model
|
|
)
|
|
for chunk in generator:
|
|
for value in chunk.values:
|
|
all_values.append(value)
|
|
return all_values
|
|
|
|
|
|
@add_method(Case)
|
|
def grid_property_async(
|
|
self,
|
|
property_type: PropertyType,
|
|
property_name: str,
|
|
time_step: int,
|
|
grid_index: int = 0,
|
|
porosity_model: PorosityModelType = PorosityModelType.MATRIX_MODEL,
|
|
) -> Iterator[Properties_pb2.PropertyChunk]:
|
|
"""Get a cell property for all grid cells. Async, so returns an iterator. For argument details, see :ref:`Result Definition <result-definition-label>`
|
|
|
|
Arguments:
|
|
property_type(str): string enum
|
|
property_name(str): name of an Eclipse property
|
|
time_step(int): the time step for which to get the property for
|
|
gridIndex(int): index to the grid we're getting values for
|
|
porosity_model(str): string enum
|
|
|
|
Returns:
|
|
An iterator to a chunk object containing an array of double values
|
|
Loop through the chunks and then the values within the chunk to get all values.
|
|
"""
|
|
property_type_enum = Properties_pb2.PropertyType.Value(property_type)
|
|
porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model)
|
|
request = Properties_pb2.PropertyRequest(
|
|
case_request=self.__request(),
|
|
property_type=property_type_enum,
|
|
property_name=property_name,
|
|
time_step=time_step,
|
|
grid_index=grid_index,
|
|
porosity_model=porosity_model_enum,
|
|
)
|
|
for chunk in self.__properties_stub.GetGridProperty(request):
|
|
yield chunk
|
|
|
|
|
|
@add_method(Case)
|
|
def grid_property(
|
|
self,
|
|
property_type: PropertyType,
|
|
property_name: str,
|
|
time_step: int,
|
|
grid_index: int = 0,
|
|
porosity_model: PorosityModelType = PorosityModelType.MATRIX_MODEL,
|
|
) -> List[float]:
|
|
"""Get a cell property for all grid cells. Synchronous, so returns a list. For argument details, see :ref:`Result Definition <result-definition-label>`
|
|
|
|
Arguments:
|
|
property_type(str): string enum
|
|
property_name(str): name of an Eclipse property
|
|
time_step(int): the time step for which to get the property for
|
|
grid_index(int): index to the grid we're getting values for
|
|
porosity_model(str): string enum
|
|
|
|
Returns:
|
|
A list of double values
|
|
"""
|
|
all_values = []
|
|
generator = self.grid_property_async(
|
|
property_type, property_name, time_step, grid_index, porosity_model
|
|
)
|
|
for chunk in generator:
|
|
for value in chunk.values:
|
|
all_values.append(value)
|
|
return all_values
|
|
|
|
|
|
@add_method(Case)
|
|
def set_active_cell_property_async(
|
|
self,
|
|
values_iterator: Iterable[List[float]],
|
|
property_type: PropertyType,
|
|
property_name: str,
|
|
time_step: int,
|
|
porosity_model: PorosityModelType = PorosityModelType.MATRIX_MODEL,
|
|
data_type: PropertyDataType = PropertyDataType.FLOAT,
|
|
) -> None:
|
|
"""Set cell property for all active cells Async. Takes an iterator to the input values. For argument details, see :ref:`Result Definition <result-definition-label>`
|
|
|
|
Arguments:
|
|
values_iterator(iterator): an iterator to the properties to be set
|
|
property_type(str): string enum
|
|
property_name(str): name of an Eclipse property
|
|
time_step(int): the time step for which to get the property for
|
|
porosity_model(str): string enum
|
|
data_type(str): property data type ("FLOAT" or "INTEGER"). Use "INTEGER" to create a discrete/category property.
|
|
"""
|
|
property_type_enum = Properties_pb2.PropertyType.Value(property_type)
|
|
porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model)
|
|
data_type_enum = Properties_pb2.PropertyDataType.Value(data_type)
|
|
request = Properties_pb2.PropertyRequest(
|
|
case_request=self.__request(),
|
|
property_type=property_type_enum,
|
|
property_name=property_name,
|
|
time_step=time_step,
|
|
porosity_model=porosity_model_enum,
|
|
data_type=data_type_enum,
|
|
)
|
|
|
|
request_iterator = self.__generate_property_input_iterator(values_iterator, request)
|
|
self.__properties_stub.SetActiveCellProperty(request_iterator)
|
|
|
|
|
|
@add_method(Case)
|
|
def set_active_cell_property(
|
|
self,
|
|
values: List[float],
|
|
property_type: PropertyType,
|
|
property_name: str,
|
|
time_step: int,
|
|
porosity_model: PorosityModelType = PorosityModelType.MATRIX_MODEL,
|
|
data_type: PropertyDataType = PropertyDataType.FLOAT,
|
|
) -> None:
|
|
"""Set a cell property for all active cells. For argument details, see :ref:`Result Definition <result-definition-label>`
|
|
|
|
Arguments:
|
|
values(list): a list of double precision floating point numbers
|
|
property_type(str): string enum
|
|
property_name(str): name of an Eclipse property
|
|
time_step(int): the time step for which to get the property for
|
|
porosity_model(str): string enum
|
|
data_type(str): property data type ("FLOAT" or "INTEGER"). Use "INTEGER" to create a discrete/category property.
|
|
"""
|
|
property_type_enum = Properties_pb2.PropertyType.Value(property_type)
|
|
porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model)
|
|
data_type_enum = Properties_pb2.PropertyDataType.Value(data_type)
|
|
request = Properties_pb2.PropertyRequest(
|
|
case_request=self.__request(),
|
|
property_type=property_type_enum,
|
|
property_name=property_name,
|
|
time_step=time_step,
|
|
porosity_model=porosity_model_enum,
|
|
data_type=data_type_enum,
|
|
)
|
|
request_iterator = self.__generate_property_input_chunks(values, request)
|
|
reply = self.__properties_stub.SetActiveCellProperty(request_iterator)
|
|
if reply.accepted_value_count < len(values):
|
|
raise IndexError
|
|
|
|
|
|
@add_method(Case)
|
|
def set_grid_property(
|
|
self,
|
|
values: List[float],
|
|
property_type: PropertyType,
|
|
property_name: str,
|
|
time_step: int,
|
|
grid_index: int = 0,
|
|
porosity_model: PorosityModelType = PorosityModelType.MATRIX_MODEL,
|
|
data_type: PropertyDataType = PropertyDataType.FLOAT,
|
|
) -> None:
|
|
"""Set a cell property for all grid cells. For argument details, see :ref:`Result Definition <result-definition-label>`
|
|
|
|
Arguments:
|
|
values(list): a list of double precision floating point numbers
|
|
property_type(str): string enum
|
|
property_name(str): name of an Eclipse property
|
|
time_step(int): the time step for which to get the property for
|
|
grid_index(int): index to the grid we're setting values for
|
|
porosity_model(str): string enum
|
|
data_type(str): property data type ("FLOAT" or "INTEGER"). Use "INTEGER" to create a discrete/category property.
|
|
"""
|
|
property_type_enum = Properties_pb2.PropertyType.Value(property_type)
|
|
porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model)
|
|
data_type_enum = Properties_pb2.PropertyDataType.Value(data_type)
|
|
request = Properties_pb2.PropertyRequest(
|
|
case_request=self.__request(),
|
|
property_type=property_type_enum,
|
|
property_name=property_name,
|
|
time_step=time_step,
|
|
grid_index=grid_index,
|
|
porosity_model=porosity_model_enum,
|
|
data_type=data_type_enum,
|
|
)
|
|
request_iterator = self.__generate_property_input_chunks(values, request)
|
|
reply = self.__properties_stub.SetGridProperty(request_iterator)
|
|
if reply.accepted_value_count < len(values):
|
|
raise IndexError
|
|
|
|
|
|
@add_method(Case)
|
|
def create_well_bore_stability_plot(
|
|
self,
|
|
well_path: str,
|
|
time_step: int,
|
|
parameters: Optional[WbsParameters] = None,
|
|
) -> Optional[WellBoreStabilityPlot]:
|
|
"""Create a new well bore stability plot
|
|
|
|
Arguments:
|
|
well_path(str): well path name
|
|
time_step(int): time step
|
|
|
|
Returns:
|
|
:class:`rips.generated.generated_classes.WellBoreStabilityPlot`
|
|
"""
|
|
pb2_parameters = None
|
|
if parameters is not None:
|
|
assert isinstance(parameters, WbsParameters)
|
|
pb2_parameters = parameters.pb2_object()
|
|
|
|
plot_result = self._execute_command(
|
|
createWellBoreStabilityPlot=Cmd.CreateWbsPlotRequest(
|
|
caseId=self.id,
|
|
wellPath=well_path,
|
|
timeStep=time_step,
|
|
wbsParameters=pb2_parameters,
|
|
)
|
|
)
|
|
project = self.ancestor(rips.project.Project)
|
|
plot = project.plot(view_id=plot_result.createWbsPlotResult.viewId)
|
|
return plot
|
|
|
|
|
|
@add_method(Case)
|
|
def import_formation_names(
|
|
self, formation_files: Optional[Union[str, List[str]]] = None
|
|
) -> None:
|
|
"""Import formation names into project and apply it to the current case
|
|
|
|
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=Cmd.ImportFormationNamesRequest(
|
|
formationFiles=formation_files, applyToCaseId=self.id
|
|
)
|
|
)
|
|
|
|
|
|
@add_method(Case)
|
|
def simulation_wells(self) -> List[SimulationWell]:
|
|
"""Get a list of all simulation wells for a case
|
|
|
|
Returns:
|
|
:class:`rips.generated.generated_classes.SimulationWell`
|
|
|
|
"""
|
|
if self.views():
|
|
# Use the first view to get simulation wells.
|
|
return self.views()[0].descendants(SimulationWell)
|
|
return []
|
|
|
|
|
|
@add_method(Case)
|
|
def active_cell_centers_async(
|
|
self, porosity_model: PorosityModelType = PorosityModelType.MATRIX_MODEL
|
|
) -> Iterator[Definitions_pb2.CellCenters]:
|
|
"""Get a cell centers for all active cells. Async, so returns an iterator
|
|
|
|
Arguments:
|
|
porosity_model(str): string enum. See available()
|
|
|
|
Returns:
|
|
An iterator to a chunk object containing an array of Vec3d values.
|
|
Loop through the chunks and then the values within the chunk to get all values.
|
|
"""
|
|
porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model)
|
|
request = Case_pb2.CellInfoRequest(
|
|
case_request=self.__request(), porosity_model=porosity_model_enum
|
|
)
|
|
return self.__case_stub.GetCellCenterForActiveCells(request)
|
|
|
|
|
|
@add_method(Case)
|
|
def active_cell_centers(
|
|
self, porosity_model: PorosityModelType = PorosityModelType.MATRIX_MODEL
|
|
) -> List[Definitions_pb2.Vec3d]:
|
|
"""Get a cell centers for all active cells. Synchronous, so returns a list.
|
|
|
|
Arguments:
|
|
porosity_model(str): string enum. See available()
|
|
|
|
Returns:
|
|
A list of Vec3d
|
|
"""
|
|
cell_centers = []
|
|
generator = self.active_cell_centers_async(porosity_model)
|
|
for chunk in generator:
|
|
for value in chunk.centers:
|
|
cell_centers.append(value)
|
|
return cell_centers
|
|
|
|
|
|
@add_method(Case)
|
|
def active_cell_corners_async(
|
|
self, porosity_model: PorosityModelType = PorosityModelType.MATRIX_MODEL
|
|
) -> Iterator[Definitions_pb2.CellCornersArray]:
|
|
"""Get a cell corners for all active cells. Async, so returns an iterator
|
|
|
|
Arguments:
|
|
porosity_model(str): string enum. See available()
|
|
|
|
Returns:
|
|
An iterator to a chunk object containing an array of CellCorners (which is eight Vec3d values).
|
|
Loop through the chunks and then the values within the chunk to get all values.
|
|
"""
|
|
porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model)
|
|
request = Case_pb2.CellInfoRequest(
|
|
case_request=self.__request(), porosity_model=porosity_model_enum
|
|
)
|
|
return self.__case_stub.GetCellCornersForActiveCells(request)
|
|
|
|
|
|
@add_method(Case)
|
|
def active_cell_corners(
|
|
self, porosity_model: PorosityModelType = PorosityModelType.MATRIX_MODEL
|
|
) -> List[Definitions_pb2.CellCorners]:
|
|
"""Get a cell corners for all active cells. Synchronous, so returns a list.
|
|
|
|
Arguments:
|
|
porosity_model(str): string enum. See available()
|
|
|
|
**CellCorner class description**::
|
|
|
|
Parameter | Description | Type
|
|
----------- | ------------ | -----
|
|
c0 | | Vec3d
|
|
c1 | | Vec3d
|
|
c2 | | Vec3d
|
|
c3 | | Vec3d
|
|
c4 | | Vec3d
|
|
c5 | | Vec3d
|
|
c6 | | Vec3d
|
|
c7 | | Vec3d
|
|
|
|
|
|
"""
|
|
cell_corners = []
|
|
generator = self.active_cell_corners_async(porosity_model)
|
|
for chunk in generator:
|
|
for value in chunk.cells:
|
|
cell_corners.append(value)
|
|
return cell_corners
|
|
|
|
|
|
@add_method(Case)
|
|
def selected_cells_async(self) -> Iterator[Case_pb2.SelectedCells]:
|
|
"""Get the selected cells. Async, so returns an iterator.
|
|
|
|
Returns:
|
|
An iterator to a chunk object containing an array of cells.
|
|
Loop through the chunks and then the cells within the chunk to get all cells.
|
|
"""
|
|
return self.__case_stub.GetSelectedCells(self.__request())
|
|
|
|
|
|
@add_method(Case)
|
|
def selected_cells(self) -> List[Case_pb2.SelectedCell]:
|
|
"""Get the selected cells. Synchronous, so returns a list.
|
|
|
|
Returns:
|
|
A list of Cells.
|
|
"""
|
|
cells = []
|
|
generator = self.selected_cells_async()
|
|
for chunk in generator:
|
|
for value in chunk.cells:
|
|
cells.append(value)
|
|
return cells
|
|
|
|
|
|
@add_method(Case)
|
|
def coarsening_info(self) -> List[Case_pb2.CoarseningInfo]:
|
|
"""Get a coarsening information for all grids in the case.
|
|
|
|
Returns:
|
|
A list of CoarseningInfo objects with two Vec3i min and max objects
|
|
for each entry.
|
|
"""
|
|
return self.__case_stub.GetCoarseningInfoArray(self.__request()).data
|
|
|
|
|
|
@add_method(Case)
|
|
def available_nnc_properties(self) -> List[NNCProperties_pb2.AvailableNNCProperty]:
|
|
"""Get a list of available NNC properties
|
|
|
|
**NNCConnection class description**::
|
|
|
|
Parameter | Description | Type
|
|
------------------------| --------------------------------------------- | -----
|
|
cell_grid_index1 | Reservoir Cell Index to cell 1 | int32
|
|
cell_grid_index2 | Reservoir Cell Index to cell 2 | int32
|
|
cell1 | Reservoir Cell IJK to cell 1 | Vec3i
|
|
cell2 | Reservoir Cell IJK to cell 1 | Vec3i
|
|
|
|
"""
|
|
return self.__nnc_properties_stub.GetAvailableNNCProperties(
|
|
self.__request()
|
|
).properties
|
|
|
|
|
|
@add_method(Case)
|
|
def nnc_connections_async(self) -> Iterator[NNCProperties_pb2.NNCConnections]:
|
|
"""Get the NNC connections. Async, so returns an iterator.
|
|
|
|
Returns:
|
|
An iterator to a chunk object containing an array NNCConnection objects.
|
|
Loop through the chunks and then the connection within the chunk to get all connections.
|
|
"""
|
|
return self.__nnc_properties_stub.GetNNCConnections(self.__request())
|
|
|
|
|
|
@add_method(Case)
|
|
def nnc_connections(self) -> List[NNCProperties_pb2.NNCConnection]:
|
|
"""Get the NNC connection. Synchronous, so returns a list.
|
|
|
|
Returns:
|
|
A list of NNCConnection objects.
|
|
"""
|
|
connections = []
|
|
generator = self.nnc_connections_async()
|
|
for chunk in generator:
|
|
for value in chunk.connections:
|
|
connections.append(value)
|
|
return connections
|
|
|
|
|
|
@add_method(Case)
|
|
def __nnc_connections_values_async(
|
|
self, property_name: str, property_type: int, time_step: int
|
|
) -> Iterator[NNCProperties_pb2.NNCValues]:
|
|
request = NNCProperties_pb2.NNCValuesRequest(
|
|
case_id=self.id,
|
|
property_name=property_name,
|
|
property_type=property_type,
|
|
time_step=time_step,
|
|
)
|
|
return self.__nnc_properties_stub.GetNNCValues(request)
|
|
|
|
|
|
@add_method(Case)
|
|
def __nnc_values_generator_to_list(
|
|
self, generator: Iterable[NNCProperties_pb2.NNCValues]
|
|
) -> List[float]:
|
|
"""Converts a NNC values generator to a list."""
|
|
vals = []
|
|
for chunk in generator:
|
|
for value in chunk.values:
|
|
vals.append(value)
|
|
return vals
|
|
|
|
|
|
@add_method(Case)
|
|
def nnc_connections_static_values_async(
|
|
self, property_name: str
|
|
) -> Iterator[NNCProperties_pb2.NNCValues]:
|
|
"""Get the static NNC values. Async, so returns an iterator.
|
|
|
|
Returns:
|
|
An iterator to a chunk object containing an list of doubles.
|
|
Loop through the chunks and then the values within the chunk to get values
|
|
for all the connections. The order of the list matches the list from
|
|
nnc_connections, i.e. the nth object of nnc_connections() refers to nth
|
|
value in this list.
|
|
"""
|
|
return self.__nnc_connections_values_async(
|
|
property_name, NNCProperties_pb2.NNC_STATIC, 0
|
|
)
|
|
|
|
|
|
@add_method(Case)
|
|
def nnc_connections_static_values(self, property_name: str) -> List[float]:
|
|
"""Get the static NNC values.
|
|
|
|
Returns:
|
|
A list of doubles. The order of the list matches the list from
|
|
nnc_connections, i.e. the nth object of nnc_connections() refers to nth
|
|
value in this list.
|
|
"""
|
|
generator = self.nnc_connections_static_values_async(property_name)
|
|
return self.__nnc_values_generator_to_list(generator)
|
|
|
|
|
|
@add_method(Case)
|
|
def nnc_connections_dynamic_values_async(
|
|
self, property_name: str, time_step: int
|
|
) -> Iterator[NNCProperties_pb2.NNCValues]:
|
|
"""Get the dynamic NNC values. Async, so returns an iterator.
|
|
|
|
Returns:
|
|
An iterator to a chunk object containing an list of doubles.
|
|
Loop through the chunks and then the values within the chunk to get values
|
|
for all the connections. The order of the list matches the list from
|
|
nnc_connections, i.e. the nth object of nnc_connections() refers to nth
|
|
value in this list.
|
|
"""
|
|
return self.__nnc_connections_values_async(
|
|
property_name, NNCProperties_pb2.NNC_DYNAMIC, time_step
|
|
)
|
|
|
|
|
|
@add_method(Case)
|
|
def nnc_connections_dynamic_values(
|
|
self, property_name: str, time_step: int
|
|
) -> List[float]:
|
|
"""Get the dynamic NNC values.
|
|
|
|
Returns:
|
|
A list of doubles. The order of the list matches the list from
|
|
nnc_connections, i.e. the nth object of nnc_connections() refers to nth
|
|
value in this list.
|
|
"""
|
|
generator = self.nnc_connections_dynamic_values_async(property_name, time_step)
|
|
return self.__nnc_values_generator_to_list(generator)
|
|
|
|
|
|
@add_method(Case)
|
|
def nnc_connections_generated_values_async(
|
|
self, property_name: str, time_step: int
|
|
) -> Iterator[NNCProperties_pb2.NNCValues]:
|
|
"""Get the generated NNC values. Async, so returns an iterator.
|
|
|
|
Returns:
|
|
An iterator to a chunk object containing an list of doubles.
|
|
Loop through the chunks and then the values within the chunk to get values
|
|
for all the connections. The order of the list matches the list from
|
|
nnc_connections, i.e. the nth object of nnc_connections() refers to nth
|
|
value in this list.
|
|
"""
|
|
return self.__nnc_connections_values_async(
|
|
property_name, NNCProperties_pb2.NNC_GENERATED, time_step
|
|
)
|
|
|
|
|
|
@add_method(Case)
|
|
def nnc_connections_generated_values(
|
|
self, property_name: str, time_step: int
|
|
) -> List[float]:
|
|
"""Get the generated NNC values.
|
|
|
|
Returns:
|
|
A list of doubles. The order of the list matches the list from
|
|
nnc_connections, i.e. the nth object of nnc_connections() refers to nth
|
|
value in this list.
|
|
"""
|
|
generator = self.nnc_connections_generated_values_async(property_name, time_step)
|
|
return self.__nnc_values_generator_to_list(generator)
|
|
|
|
|
|
@add_method(Case)
|
|
def __generate_nnc_property_input_chunks(
|
|
self, array: List[float], parameters: NNCProperties_pb2.NNCValuesInputRequest
|
|
) -> Iterator[NNCProperties_pb2.NNCValuesChunk]:
|
|
index = -1
|
|
while index < len(array):
|
|
chunk = NNCProperties_pb2.NNCValuesChunk()
|
|
if index == -1:
|
|
chunk.params.CopyFrom(parameters)
|
|
index += 1
|
|
else:
|
|
actual_chunk_size = min(len(array) - index + 1, self.chunk_size)
|
|
chunk.values.CopyFrom(
|
|
NNCProperties_pb2.NNCValues(
|
|
values=array[index : index + actual_chunk_size]
|
|
)
|
|
)
|
|
index += actual_chunk_size
|
|
|
|
yield chunk
|
|
# Final empty message to signal completion
|
|
chunk = NNCProperties_pb2.NNCValuesChunk()
|
|
yield chunk
|
|
|
|
|
|
@add_method(Case)
|
|
def set_nnc_connections_values(
|
|
self,
|
|
values: List[float],
|
|
property_name: str,
|
|
time_step: int,
|
|
porosity_model: PorosityModelType = PorosityModelType.MATRIX_MODEL,
|
|
) -> None:
|
|
"""Set nnc connection values for all connections..
|
|
|
|
Arguments:
|
|
values(list): a list of double precision floating point numbers
|
|
property_name(str): name of an Eclipse property
|
|
time_step(int): the time step for which to get the property for
|
|
porosity_model(str): string enum. See available()
|
|
"""
|
|
porosity_model_enum = Case_pb2.PorosityModelType.Value(porosity_model)
|
|
request = NNCProperties_pb2.NNCValuesInputRequest(
|
|
case_id=self.id,
|
|
property_name=property_name,
|
|
time_step=time_step,
|
|
porosity_model=porosity_model_enum,
|
|
)
|
|
request_iterator = self.__generate_nnc_property_input_chunks(values, request)
|
|
reply = self.__nnc_properties_stub.SetNNCValues(request_iterator)
|
|
if reply.accepted_value_count < len(values):
|
|
raise IndexError
|
|
|
|
|
|
@add_method(Reservoir)
|
|
def grid_property_for_positions(
|
|
self,
|
|
positions: List[List[float]],
|
|
property_type: PropertyType,
|
|
property_name: str,
|
|
time_step: int,
|
|
porosity_model: PorosityModelType = PorosityModelType.MATRIX_MODEL,
|
|
) -> List[float]:
|
|
shared_uuid = uuid.uuid4()
|
|
coordinate_x = "{}_{}".format(shared_uuid, "coordinate_x")
|
|
coordinate_y = "{}_{}".format(shared_uuid, "coordinate_y")
|
|
coordinate_z = "{}_{}".format(shared_uuid, "coordinate_z")
|
|
result_key = "{}_{}".format(shared_uuid, "result")
|
|
|
|
coord_x = []
|
|
coord_y = []
|
|
coord_z = []
|
|
for pos in positions:
|
|
coord_x.append(pos[0])
|
|
coord_y.append(pos[1])
|
|
coord_z.append(pos[2])
|
|
|
|
# Get the results from the key-value store.
|
|
project = self.ancestor(Project)
|
|
if project:
|
|
project.set_key_values(coordinate_x, coord_x)
|
|
project.set_key_values(coordinate_y, coord_y)
|
|
project.set_key_values(coordinate_z, coord_z)
|
|
|
|
self.export_values_internal(
|
|
coordinate_x=coordinate_x,
|
|
coordinate_y=coordinate_y,
|
|
coordinate_z=coordinate_z,
|
|
result_key=result_key,
|
|
property_type=property_type,
|
|
property_name=property_name,
|
|
time_step=time_step,
|
|
porosity_model=porosity_model,
|
|
)
|
|
result = project.key_values(result_key)
|
|
|
|
project.remove_key_values(coordinate_x)
|
|
project.remove_key_values(coordinate_y)
|
|
project.remove_key_values(coordinate_z)
|
|
project.remove_key_values(result_key)
|
|
|
|
return result
|
|
else:
|
|
return []
|
|
|
|
|
|
@add_method(Reservoir)
|
|
def export_corner_point_grid(
|
|
self,
|
|
) -> Tuple[List[float], List[float], List[int], int, int, int]:
|
|
"""Export corner point grid data from case
|
|
|
|
Returns:
|
|
Tuple of (zcorn, coord, actnum, nx, ny, nz) where:
|
|
- zcorn: Corner depths as defined by the Eclipse keyword ZCORN
|
|
- coord: Coordinate lines as COORD keyword in Eclipse
|
|
- actnum: Active cell info: cells with values > 0 are active
|
|
- nx, ny, nz: Grid dimensions in I, J, K directions
|
|
"""
|
|
shared_uuid = uuid.uuid4()
|
|
zcorn_key = "{}_{}".format(shared_uuid, "zcorn")
|
|
coord_key = "{}_{}".format(shared_uuid, "coord")
|
|
actnum_key = "{}_{}".format(shared_uuid, "actnum")
|
|
|
|
# Call internal C++ method to populate key-value store
|
|
self.export_corner_point_grid_internal(
|
|
zcorn_key=zcorn_key, coord_key=coord_key, actnum_key=actnum_key
|
|
)
|
|
|
|
# Retrieve results from key-value store
|
|
project = self.ancestor(Project)
|
|
if project:
|
|
zcorn = project.key_values(zcorn_key)
|
|
coord = project.key_values(coord_key)
|
|
actnum_raw = project.key_values(actnum_key)
|
|
actnum = [int(x) for x in actnum_raw]
|
|
|
|
# Retrieve grid dimensions
|
|
dimensions_key = zcorn_key + "_dimensions"
|
|
dimensions = project.key_values(dimensions_key)
|
|
nx, ny, nz = int(dimensions[0]), int(dimensions[1]), int(dimensions[2])
|
|
|
|
# Clean up
|
|
project.remove_key_values(zcorn_key)
|
|
project.remove_key_values(coord_key)
|
|
project.remove_key_values(actnum_key)
|
|
project.remove_key_values(dimensions_key)
|
|
|
|
return (zcorn, coord, actnum, nx, ny, nz)
|
|
else:
|
|
return ([], [], [], 0, 0, 0)
|
|
|
|
|
|
@add_method(Case)
|
|
def replace_corner_point_grid(
|
|
self,
|
|
nx: int,
|
|
ny: int,
|
|
nz: int,
|
|
coord: List[float],
|
|
zcorn: List[float],
|
|
actnum: List[int],
|
|
):
|
|
"""Replace the current case grid with new corner point grid geometry
|
|
|
|
This method modifies the geometry of an existing case by replacing it with
|
|
new grid parameters. All existing properties will be cleared.
|
|
|
|
Arguments:
|
|
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")
|
|
|
|
# Get project to access key-value store
|
|
project = self.ancestor(rips.project.Project)
|
|
if not project:
|
|
raise RuntimeError("Unable to get project from case")
|
|
|
|
# Store arrays in key-value store
|
|
project.set_key_values(coord_key, coord)
|
|
project.set_key_values(zcorn_key, zcorn)
|
|
project.set_key_values(actnum_key, actnum)
|
|
|
|
# Call internal C++ method to replace the grid
|
|
self.replace_corner_point_grid_internal(
|
|
nx=nx,
|
|
ny=ny,
|
|
nz=nz,
|
|
coord_key=coord_key,
|
|
zcorn_key=zcorn_key,
|
|
actnum_key=actnum_key,
|
|
)
|
|
|
|
|
|
@add_method(EclipseCase)
|
|
def filtered_cells(self, filter, time_step: int = 0, grid_index: int = 0) -> List[int]:
|
|
"""Apply a cell filter to this case and return a per-cell 0/1 mask.
|
|
|
|
The returned list has the same length and ordering as
|
|
``case.grid_property("STATIC_NATIVE", "PERMX", grid_index)``, so the two
|
|
vectors can be combined element-wise.
|
|
|
|
Arguments:
|
|
filter (CellFilter): The cell filter to apply (e.g. a CombinedFilter
|
|
obtained from ``case.data_filter_collection().filters()``).
|
|
time_step (int): Time step index used by property-filter children.
|
|
grid_index (int): Grid index (0 = main grid, >0 = LGRs).
|
|
|
|
Returns:
|
|
List[int]: 1 if the cell passes the filter, 0 otherwise.
|
|
"""
|
|
mask_key = "{}_{}".format(uuid.uuid4(), "filtered_cells")
|
|
project = self.ancestor(rips.project.Project)
|
|
if not project:
|
|
raise RuntimeError("Unable to get project from case")
|
|
try:
|
|
self.filtered_cells_internal(
|
|
filter=filter,
|
|
mask_key=mask_key,
|
|
time_step=time_step,
|
|
grid_index=grid_index,
|
|
)
|
|
return [int(v) for v in project.key_values(mask_key)]
|
|
finally:
|
|
project.remove_key_values(mask_key)
|