User Guide
Corner-point Grid
A corner-point grid is a tessellation of a 3D volume where each cell is a hexahedron.
Each cell is identified by a integer coordinate (i,j,k).
For each i,j there is are four straight lines, defined by their end-points
called a pillar. The end-points form two surfaces, one
for the top end-points and one for the bottom end points, which
are in the resfo_utilities.CornerpointGrid.coord array.
For the cell at position i,j,k, its eight corner vertices are defined by
giving the z values along the pillars at [(i,j), (i+1, j), (i, j+1), (i+1, j+1)]
which are in the resfo_utilities.CornerpointGrid.zcorn array.
Usually, a corner-point grid contains x,y values that needs to be transformed
into a map coordinate system (which could be UTM-coordinates). That
coordinate system is represented by resfo_utilities.MapAxes.
- class resfo_utilities.CornerpointGrid(coord: npt.NDArray[np.float32], zcorn: npt.NDArray[np.float32], map_axes: MapAxes | None = None)
-
- coord
A (ni+1, nj+1, 2, 3) array where coord[i,j,0] is the top end point of the i,j pillar and coord[i,j,1] is the corresponding bottom end point.
- Type:
numpy.ndarray[tuple[Any, …], numpy.dtype[numpy.float32]]
- zcorn
A (ni, nj, nk, 8) array where zcorn[i,j,k] is the z value of the 8 corners of the cell at i,j,k. The order of the corner z values are as follows: [TSW, TSE, TNW, TNE, BSW, BSE, BNW, BNE] where N(orth) means higher y, E(east) means higher x, T(op) means lower z (when z is interpreted as depth).
- Type:
numpy.ndarray[tuple[Any, …], numpy.dtype[numpy.float32]]
- map_axes
Optionally each point is interpreted to be relative to some map coordinate system. Defaults to the unit coordinate system with origin at (0,0).
- Type:
- Raises:
InvalidGridError – If coord or zcorn does not have correct shape.
- cell_corners(i: int, j: int, k: int) npt.NDArray[np.float32]
Array of coordinates for all corners of the cell at i,j,k
The order of the corners are the same as in zcorn.
- find_cell_containing_point(points: ArrayLike, map_coordinates: bool = True, tolerance: float = 1e-06) list[tuple[int, int, int] | None]
Find a cell in the grid which contains the given point.
- Parameters:
points – The points to find cells for.
map_coordinates – Whether points are in the map coordinate system. Defaults to True.
tolerance – The maximum distance to the cell boundary a point can have to be considered to be contained in the cell.
- Returns:
list of i,j,k indices for each point (or None if the point is not contained in any cell.
- point_in_cell(points: npt.ArrayLike, i: int, j: int, k: int, tolerance: float = 1e-06, map_coordinates: bool = True) npt.NDArray[np.bool_]
Whether the points (x,y,z) is in the cell at (i,j,k).
For containment the cell are considered to have bilinear faces.
- Param:
- points:
x,y,z triple or array of x,y,z triples to be tested for containment.
- tolerance:
The tolerance used for numerical precision in the linear interpolation calculation.
- map_coordinates:
Whether the given points are in the mapaxes coordinate system, defaults to true.
- Returns:
Array of boolean values for each triplet describing whether it is contained in the cell.
- classmethod read_egrid(file_like: str | PathLike[str] | IO[Any]) Self
Read the global grid from an .EGRID or .FEGRID file.
If the EGRID contains Local Grid Refinements or Coarsening Groups, that is silently ignored and only the host grid is read. Radial grids are not supported and will cause InvalidEgridFileError to be raised.
- Parameters:
file_like – The EGRID file, could either be a filename, pathlike or an opened EGRID file. The function also handles formatted egrid files (.FEGRID). Whether the file is formatted or not is determined by looking at the extension a filepath is given and by whether the stream is a byte-stream (unformatted) or a text-stream when an opened file is given.
- Raises:
InvalidEgridFileError – When the egrid file is not valid, or contains a radial grid.
OSError – If the given filepath cannot be opened.
- class resfo_utilities.MapAxes(y_axis: tuple[float32, float32], origin: tuple[float32, float32], x_axis: tuple[float32, float32])
The axes of the map coordinate system.
Note that regardless of the size of the axes, when transforming from the grid coordinate system to the map coordinate system, scaling is not applied.
- y_axis
A point along the map y axis.
- Type:
tuple[numpy.float32, numpy.float32]
- origin
The origin of the map coordinate system.
- Type:
tuple[numpy.float32, numpy.float32]
- x_axis
A point along the map x axis.
- Type:
tuple[numpy.float32, numpy.float32]
- transform_map_points(points: npt.NDArray[np.float32]) npt.NDArray[np.float32]
Transforms points from map coordinates to grid coordinates.
Scaling according to length of the axes is not applied.
- Returns:
The given map points in the grid coordinate system.
Summaries
The summary files contain a number of time vectors. There is a
.SMSPEC (or .FSMSPEC for formatted files) which
describes what is in each time vector, and what the start date is.
The time vector is guaranteed to have one value for each report
step (described in the schedule section of the .DATA file),
but could have additional values at times between the
report steps called ministeps.
Summary files can also be unified or split. A unified summary
file has the extenion .UNSMRY (or .FUNSMRY for formatted files)
and is enabled by adding the keyword UNIFOUT to the .DATA file.
For split summaries there is one file for each report step, named .S0001,
.S0002 and so on (.A0001 for formatted files).
SummaryReader lazily reads these files, and
and can look for what combination of split and formatted
files are present:
from resfo_utilities import SummaryReader
summary = SummaryReader("BASENAME")
print(f"The start date is {summary.start_date}")
for step, val in enumerate(summary.values()):
print(f"For step {step}:")
for kw, v in zip(summary.summary_keywords, val):
print(f" The keyword {kw} had the value {v}")
This will print all the summary vectors produced from
BASENAME.DATA (regardless of whether it is .UNSMRY, .FUNSMRY, etc.)
See OPM Flow manual section F for details.
- class resfo_utilities.SummaryReader(*, case_path: str | PathLike[str], smspec: None = None, summaries: None = None)
- class resfo_utilities.SummaryReader(*, smspec: Callable[[], IO[Any]], summaries: Iterable[Callable[[], IO[Any]]], case_path: None = None)
Reader for summary files.
Each file is opened when the corresponding data is requested so asking for the properties of SummaryReader may raise InvalidSummaryError if the corresponding file or its content is invalid.
- property smspec_filename: str
The filename of the summary spec file.
e.g. “CASE.SMSPEC”
- property start_date: datetime
The start date of the simulation.
- property summary_filenames: Iterator[str]
The filename of the summary file(s).
e.g. [“CASE.UNSMRY”] for unified or [“CASE.S0001”, “CASE.S0002”] for split.
- property summary_keywords: list[SummaryKeyword]
The list of keywords in the summary.
- values(report_step_only: bool = True) Iterator[ndarray[tuple[Any, ...], dtype[float32]]]
Iterate over the values for the summary keywords.
- Parameters:
report_step_only – If
True, yield only at report steps (DATES).- Yields:
arrays of the keyword values in the order of the summary_keywords.
- Raises:
InvalidSummaryError – If the summary files cannot be read from or contains invalid contents.
- class resfo_utilities.SummaryKeyword(summary_variable: str, number: int | None = None, name: str | None = None, lgr_name: str | None = None, li: int | None = None, lj: int | None = None, lk: int | None = None, unit: str | None = None)
One member of the KEYWORDS array.
- summary_variable
The variable name, eg WOPR, or FOPT.
- Type:
- number
A number associated with the keyword, eg. for block variables it is the index of the block.
- Type:
int | None
- name
A name associated with the keyword, eg. for well variables it is the name of the well.
- Type:
str | None
- lgr_name
If a local variable then the name of the Local Grid Refinement.
- Type:
str | None
- li
The i index of the host cell for the LGR.
- Type:
int | None
- lj
The j index of the host cell for the LGR.
- Type:
int | None
- lk
The k index of the host cell for the LGR.
- Type:
int | None
- unit
The units for the value of the keyword, eg. for FOPR it may be SM3/DAY.
- Type:
str | None
RFT
The RFT files contains several properties for selected wells along the well connections.
The type of properties come in three categories:
RFT, PLT and segment. For each well, any subset of
these categories may be present. Which categories
are present is controlled by the WRFT and WRFTPLT
keywords in the .DATA file.
Typical usage example:
from resfo_utilities import RFTReader
with RFTReader.open("CASE.RFT") as rft:
for entry in rft:
if "PRESSURE" in entry:
print(f"Pressure for well {entry.well} at {entry.date}:")
for pos, pressure in zip(entry.connections, entry["PRESSURE"]):
print("{pos}: {pressure} {entry.pressure_units}")
- class resfo_utilities.RFTEntry(time_since_start: timedelta, date: date, connections: ndarray[tuple[int, int], dtype[int32]], well: str, lgr_name: str | None = None, depth_units: str | None = None, pressure_units: str | None = None, types_of_data: Container[RFTDataCategory] | None = None, type_of_well: TypeOfWell | None = None, liquid_flow_rate_units: str | None = None, gas_flow_rate_units: str | None = None, local_volumetric_flow_rate_units: str | None = None, flow_velocity_units: str | None = None, liquid_and_gas_viscosity_units: str | None = None, polymer_and_brine_concentration_units: str | None = None, polymer_and_brine_flow_rate_units: str | None = None, absorbed_polymer_concentration_units: str | None = None)
A single RFT entry representing well data at a specific time.
Acts as a mapping from data array names (e.g., “PRESSURE”, “DEPTH”) to numpy arrays containing values for each connection in the well.
- Parameters:
time_since_start – Time elapsed since simulation start.
date – Calendar date of the measurement.
connections – List of (i, j, k) grid cell indices for each connection.
well – Well name.
lgr_name – Local grid refinement name, if applicable.
depth_units – Units for depth measurements.
pressure_units – Units for pressure measurements.
types_of_data – Type of test data (RFT, PLT, or SEGMENT).
type_of_well – Well completion type (STANDARD or MULTI_SEGMENT).
liquid_flow_rate_units – Units for liquid flow rates.
gas_flow_rate_units – Units for gas flow rates.
local_volumetric_flow_rate_units – Units for local volumetric flow rates.
flow_velocity_units – Units for flow velocity.
liquid_and_gas_viscosity_units – Units for viscosity.
polymer_and_brine_concentration_units – Units for polymer/brine concentration.
polymer_and_brine_flow_rate_units – Units for polymer/brine flow rates.
absorbed_polymer_concentration_units – Units for absorbed polymer concentration.
- property date: date
Calendar date of the measurement.
- property polymer_and_brine_concentration_units: str | None
Units for polymer and brine concentration.
- property time_since_start: timedelta
Time elapsed since simulation start.
- property types_of_data: Container[RFTDataCategory] | None
Types of test data (RFT, PLT, and/or SEGMENT).
- property well: str
Well name.
- class resfo_utilities.RFTReader(file_stream: IO[Any])
Reader for RFT files.
- Parameters:
file_stream – Open file stream to read from.
- classmethod open(file_like: str | PathLike[str]) Self
Open an RFT file for reading.
Automatically detects file format based on extension (.RFT or .FRFT). If no extension is provided, searches for matching files.
- Parameters:
file_like – Path to RFT file, with or without extension.
- Raises:
FileNotFoundError – If no matching RFT file is found.
Summarykeys
Some applications use a colon separated list, called a summarykey, of the required properties needed to uniquely specify a summary vector.
What properties are required is specified in OPM Flow manual section F.9.2. Summary variables are described in the OPM Flow manual section 11.1.
A summary vector is uniquely specified by giving a summary variable, and potentially one or more of the following properties: well name, region name, lgr name, block index, completion index, network name.
For example for field variables, no additional information is required so the summary key is just the variable name: FOPR, FWPR, etc. For well variables, the well name need to be specified: WOPR:WELL_NAME, WAQR:MY_WELL etc. For block variables, the index has to be given: BOPR:10,9,50. For a local completion, both the lgr name, well name, and index has to be given: LWWITH:LGR1:WELL2:3,5,5.
- resfo_utilities.make_summary_key(keyword: str, number: int | None = None, name: str | None = None, nx: int | None = None, ny: int | None = None, lgr_name: str | None = None, li: int | None = None, lj: int | None = None, lk: int | None = None) str
Converts values found in the um to the summary_key format.
>>> make_summary_key(keyword="WOPR", name="WELL1") 'WOPR:WELL1' >>> make_summary_key(keyword="BOPR", number=4, nx=2, ny=2) 'BOPR:2,2,1'
- Parameters:
keyword – Summary variable name (e.g.,
"WOPR","BPR").number – Numeric qualifier from
NUMS(cell index, region id, etc.).name – Text qualifier from
WGNAMES(well/group name).nx – Grid dimension in x for block/completion keys.
ny – Grid dimension in y for block/completion keys.
lgr_name – Local grid name for local keys.
li – Local i-index for local block/completion.
lj – Local j-index for local block/completion.
lk – Local k-index for local block/completion.
- Raises:
InvalidSummaryKeyError – If the key is invalid
- class resfo_utilities.SummaryKeyType(*values)
Summary keys are divided into types based on summary variable name.
- classmethod from_variable(summary_variable: str) SummaryKeyType
Returns the type corresponding to the given summary variable
>>> SummaryKeyType.from_variable("FOPR").name 'FIELD' >>> SummaryKeyType.from_variable("LWWIT").name 'LOCAL_WELL'