pyopmnearwell.ml.upscale module

Functionality to upscale data from an ensemble run on a radial grid to a cartesian grid.

Note: pylint: no-member is disabled, because it complains about the BaseUpscaler missing instance attributes, which are taken care of by the Upscaler protocol. pylint: pointless-string-statement is disabled, as it complains an attribute docstring in the Upscaler protocol.

class pyopmnearwell.ml.upscale.BaseUpscaler

Bases: ABC

Extract and upscale data from an array of ensemble data.

This base class provides several methods to extract features from fine-scale radial simulations and upscale to coarse cartesian cells. Depending on the type of data, this is done by averaging/summing/etc. values along all cells that correspond to a coarse cell.

Additionally, the sparsity of the dataset can be increased by taking only some timesteps/horizontal cells.

The upscaled data is usually provided in form of two np.ndarrays, one for features and one for targets.

Subclasses need to implement __init__ and (if needed) create_ds methods.

The feature array will have shape (num_ensemble_runs, num_timesteps/step_size_t, num_layers, num_xcells/step_size_x, num_features). The target array will have shape (num_ensemble_runs, num_timesteps/step_size_t, num_layers, num_xcells/step_size_x, 1)

Note: All methods assume that all cells have the same height. if this is not the

case, the methods must be overridden.

Methods

get_analytical_PI(permeabilities, ...)

_summary_

get_analytical_WI(pressures, saturations, ...)

_summary_

get_data_WI(features, pressure_index, ...[, ...])

Calculate data-driven WI from pressure and flow rate.

get_homogeneous_values(features, feature_index)

Get a feature that is homogeneous inside a layer.

get_horizontically_integrated_values(...[, ...])

Integrate feature horizontically along layers and divide by equivalent cartesian block area.

get_radii(radii_file)

Get full list of cell radii.

get_timesteps(simulation_length)

_summary_

get_vertically_averaged_values(features, ...)

Average features vertically inside each layer.

reduce_data_size(feature[, step_size_x, ...])

Reduce the size of the input feature array by selecting elements with a fixed step size.

create_ds

_abc_impl = <_abc._abc_data object>
abstract create_ds()
get_analytical_PI(permeabilities: ndarray, cell_heights: ndarray, radii: ndarray, well_radius: float) ndarray

_summary_

_extended_summary_

Args:

permeabilities (np.ndarray): Unit has to be [m^2]! cell_heights (np.ndarray): Unit [m]. radii (np.ndarray): _description_ well_radius (float): _description_

Returns:

np.ndarray: _description_

get_analytical_WI(pressures: ndarray, saturations: ndarray, permeabilities: ndarray, temperature: float, surface_density: float, radii: ndarray, well_radius: float, OPM: Path) ndarray

_summary_

_extended_summary_

Args:

pressures (np.ndarray): _description_ saturations (np.ndarray): _description_ permeabilities (np.ndarray): Unit has to be [mD]! temperature (float): _description_ surface_density (float): _description_ radii (np.ndarray): _description_ well_radius (float): _description_ OPM (pathlib.Path): _description_

Returns:

np.ndarray: _description_

get_data_WI(features: ndarray, pressure_index: int, inj_rate_index: int, angle: float = 1.0471975511965976) ndarray

Calculate data-driven WI from pressure and flow rate.

Similar functionality to ensemble.calculate_WI, but can additionally treat multiple vertical cells in a layer correctly.

Note:
  • Pressures get averaged over each layer, injection rates get summed over each layer.

  • The method automatically scales the near-well injection rate from the cake grid with angle angle to a 360° well. Furthermore, the rate is scaled from rate-per-day (which the results are in) to rate-per-second, which OPM Flow uses internally for the WI.

Args:

features (np.ndarray): _description_ pressure_index (int): _description_ inj_rate_index (int): _description_

Returns:

np.ndarray: _description_

get_homogeneous_values(features, feature_index, disregard_first_xcell: bool = True)

Get a feature that is homogeneous inside a layer.

Note: Since the feature is equal inside a layer, this method takes the first value for each layer.

Args:

features (np.ndarray): _description_ feature_index (int): _description_. disregard_first_xcell (bool): __description__. Default is True.

Returns:
np.ndarray (``shape = (num_ensemble_runs, num_timesteps, num_layers,

num_xcells)``):

get_horizontically_integrated_values(features: ndarray, cell_center_radii: ndarray, cell_boundary_radii: ndarray, feature_index: int, disregard_first_xcell: bool = True)

Integrate feature horizontically along layers and divide by equivalent cartesian block area.

Note:
  • Before integrating, the feature is averaged vertically inside each layer.

  • As the feature is averaged and not summed, the integration takes place in 2D with vertically averaged values. Hence it suffices to divide by area and not by volume.

Args:

features (np.ndarray): _description_ cell_center_radii (np.ndarray): cell_boundary_radii (np.ndarray): feature_index (int): _description_. Default is 1. disregard_first_xcell (bool): __description__. Default is True.

Returns:
np.ndarray (``shape = (num_ensemble_runs, num_timesteps, num_layers,

num_xcells)``): Features values average for each cell.

get_radii(radii_file: Path) tuple[ndarray, ndarray]

Get full list of cell radii.

get_timesteps(simulation_length: float) ndarray

_summary_

Returns:

np.ndarray (``shape = (num_timesteps,) ``): Unit: [d].

get_vertically_averaged_values(features: ndarray, feature_index, disregard_first_xcell: bool = True) ndarray

Average features vertically inside each layer.

Args:

features (np.ndarray): _description_ feature_index (int): _description_. disregard_first_xcell (bool): __description__. Default is True.

Returns:
np.ndarray (``shape = (num_ensemble_runs, num_timesteps, num_layers,

num_xcells)``):

reduce_data_size(feature: ndarray, step_size_x: int = 1, step_size_t: int = 1, random: bool = False) ndarray

Reduce the size of the input feature array by selecting elements with a fixed step size.

Args:

feature (np.ndarray): The input feature array. step_size_x (int, optional): The step size for the x-axis. Defaults to 1. step_size_t (int, optional): The step size for the t-axis. Defaults to 1. random (bool, optional): If True, select elements randomly instead of using

a fixed step size. Defaults to False. Not implemented yet.

Returns:

np.ndarray: The reduced feature array.

class pyopmnearwell.ml.upscale.Upscaler(*args, **kwargs)

Bases: Protocol

Protocol class for upscalers.

This class is used for typing of abstract attributes of BaseUpscaler. MyPy will check if subclasses of BaseUpscaler implement the following instance attributes: - num_timesteps - num_layers - num_zcells - num_xcells - single_feature_shape However, in comparison to missing abstract functions, no runtime error will be raised if they are missing.

See, e.g., https://stackoverflow.com/a/75253719 for an explanation.

Note: As of now (Python 3.11), each instance method of BaseUpscaler or a

subclass making use of one of the attributes, needs to have its self argumented annotated with Upscaler. In future python versions it should be possible to use class BaseUpscaler[Upscaler](ABC):... instead and remove these annotations.

Attributes:
angle
num_layers
num_timesteps
num_xcells
num_zcells
single_feature_shape
_abc_impl = <_abc._abc_data object>
_is_protocol = True
property angle: float
property num_layers: int
property num_timesteps: int
property num_xcells: int
property num_zcells: int
property single_feature_shape: tuple