Skip to content

minires⚓︎

Forward simulator backed by MiniRes, a two-phase (water/oil) TPFA reservoir simulator.

MiniRes (https://github.com/patnr/MiniRes) is a pure-Python toy simulator: no binary, no licence, no deck, no scratch folder. It is therefore the cheapest way to drive PET with actual two-phase flow -- in a tutorial, in CI, or as the reference case when developing a scheme -- rather than with an ODE.

Install it alongside PET with pip install PET[minires].

The simulator section of the config configures it, e.g.

[simulator]
    reporttype  = "steps"
    reportpoint = [2, 4, 6, 8, 10]
    datatype    = ["WWCT:PRD1", "WOPR:PRD1", "FWIR"]
    dt          = 0.025
    parallel    = 1

    [simulator.model]
        Nx = 32
        Ny = 32
        por = 0.2
        [[simulator.model.wells]]
            name = "INJ1"
            xy = [0.1, 0.1]
            rate = 1.0
        [[simulator.model.wells]]
            name = "PRD1"
            xy = [0.9, 0.9]
            rate = -1.0

[simulator.model] is passed to minires.ResSim as it stands (its wells are MiniRes well records), less the permeability, which is what the ensemble state supplies, one field per member.

Conventions, all of which this module owns -- MiniRes itself is agnostic:

  • Report points are step indices, 1 .. nSteps, since MiniRes takes a uniform dt. Use reporttype = "steps". A dated case can map them with reportdates.
  • Field ordering. MiniRes is C-major (x is the first axis); Eclipse, and hence most of PET's tooling, is Fortran-ordered. field_order (default "C") says which the state vector is in, and is applied on the way in and on the way out (the adjoint).
  • Data types are named as Eclipse's summary vectors, <quantity>:<well> for a well and <quantity> for the field, so observed-data files, datatype filters and localization tooling need no adaptation. Rates are positive as produced/injected, and areal (MiniRes has no thickness).
  • Units are whatever the config poses the model in. Set cdarcy = 0.008527 in [simulator.model] for metric (m, day, bar, mD, cP), as Eclipse does.

DIFFERENTIABLE = ('WOPR', 'WWPR', 'WWCT') ⚓︎

The quantities :meth:MiniRes.run_fwd_sim can also produce an adjoint for.

FIELD_QUANTITIES = ('FOPR', 'FWPR', 'FWIR', 'FOPT', 'FWPT', 'FWIT') ⚓︎

Field rates and their cumulatives.

WELL_QUANTITIES = ('WOPR', 'WWPR', 'WLPR', 'WWIR', 'WWCT', 'WBHP') ⚓︎

Per-well quantities: oil/water/liquid production rate, water injection rate, water cut, BHP.

MiniRes ⚓︎

PET forward simulator: one MiniRes run per ensemble member.

Satisfies :class:ensemble.protocols.ForwardSimulator. Every member runs on its own deepcopy of the model, so nothing is shared and the class is picklable -- which is what parallel > 1 (p_map) requires. MiniRes drops its cached pressure preconditioner on copy for exactly this reason.

Parameters:

Name Type Description Default
input_dict dict

The parsed [simulator] section. Keys:

  • dt: the time step. Required.
  • reportpoint: the step indices to report at. Required.
  • reporttype: the index's name (default "steps").
  • reportdates: optional labels to report under instead of the step indices, e.g. dates, one per report point.
  • datatype: the summary vectors to report, ref the module docstring.
  • model: what :func:build_model takes.
  • state_variable: the ensemble state that supplies the permeability (default "permx").
  • log_perm: whether that state is :math:\log K (default True).
  • field_order: the state vector's grid ordering, "C" (default) or "F".
  • s0: initial water saturation, a scalar or a field (default 0).
  • compute_adjoints: also return each datum's sensitivity to the state (default False), ref :meth:adjoint_frame.
  • levels: per-fidelity overrides of the above, for multilevel runs, selected by setup_fwd_run(level=...).
  • parallel, hpc: read by the ensemble, not by this class.
required

adjoint_frame(model, SS, PP) ⚓︎

Each datum's sensitivity to the state, as the frame the ensemble stacks into (nd, nx, ne).

MiniRes's adjoint (minires.tlm) gives the gradient of one scalar per backward sweep, at about the cost of one simulation -- so a full Jacobian costs one sweep per datum. That is affordable on the grids this simulator is for, and is what PET's adjoint-based analyses want.

Only quantities that are a function of the saturation at the well's cells are covered (:data:DIFFERENTIABLE), and only at rate-controlled completions, whose rate is then a constant of the objective. A BHP-controlled well's rate is itself a function of (S, P); that derivative has to be worked into the seed by hand, so it is refused rather than silently dropped.

records(model, SS) ⚓︎

One dict per report point, keyed by data type -- what the ensemble collects.

run_fwd_sim(state, member_index=0, **kwargs) ⚓︎

Simulate one realisation; return its records (and adjoint), or False if it failed.

set_permeability(model, state) ⚓︎

Write the member's field into the model, as its (isotropic) permeability.

setup_fwd_run(level=None, **kwargs) ⚓︎

Select the fidelity level's configuration, when the config gives levels.

well_report(model, SS) ⚓︎

Every reportable quantity, as (nWell or 1, nSteps) arrays, from the run's well operation.

MiniRes reports one total rate per completion (signed: positive injects). The phase split is the cell's fractional flow -- the same Fluid.fractional_flow the transport uses -- and the completions are summed into wells by Wells.group.

build_model(spec) ⚓︎

Build the minires.ResSim that [simulator.model] describes.

por and active may be given as scalars; the wells are MiniRes well records (xy/path, rate/bhp, rw/WI, name).