Skip to content

ps.relperm

ps.relperm.CriticalTolerance(*, value: ScalarPropertyInput) -> None

The critical-saturation tolerance (TOLCRIT), stated once for the whole model.

ps.relperm.CriticalTolerance(value=1.0e-6) counts a phase immobile where its relative permeability is 1e-6 or less.

The relative permeability at or below which a phase counts as immobile when the simulator finds a curve’s critical saturations; stated in the list or in saturation region 1’s, at relperm/1/critical_tolerance.

value is that relative permeability (dimensionless).

ps.relperm.EndpointScaling(*, curve: Literal['drainage', 'imbibition'] = 'drainage', method: Literal['two_point', 'three_point'] = 'two_point', connate_water=None, capillary_connate_water=None, connate_gas=None, capillary_connate_gas=None, critical_water=None, critical_gas=None, critical_oil_to_water=None, critical_oil_to_gas=None, maximum_water=None, maximum_gas=None, maximum_water_relperm=None, maximum_gas_relperm=None, oil_relperm_at_connate_water=None, gas_relperm_at_residual_oil=None, water_relperm_at_critical_oil=None, oil_relperm_at_critical_gas=None, oil_relperm_at_critical_water=None, maximum_gas_oil_capillary_pressure=None, maximum_oil_water_capillary_pressure=None, source: str | None = None) -> None

End-point scaling of the drainage or the imbibition curves (the whole model).

ps.relperm.EndpointScaling(connate_water=0.2, critical_water=0.25) scales every cell’s drainage curves to a connate water saturation of 0.2 and a critical one of 0.25.

curve says which: the drainage curves (the saturation functions themselves, scaled by SWL, KRG and the like) or the imbibition curves hysteresis follows (ISWL, IKRG and the like). Each array is a single value, one value per layer (held in every cell of its layer) or a full (nx, ny, nz) array, of saturations and relative permeabilities (fractions) or, for the two capillary-pressure arrays, of pressures in the model’s units; an array left out takes each cell’s own table value. Drainage scaling states its method (two- or three-point); the imbibition curves state the largest capillary pressures, and at least one array.

method is the drainage scaling’s: "two_point" or "three_point" (SCALECRS). The arrays, each a cell’s own end point (drainage card, then imbibition card): connate_water, the connate water saturation (SWL, ISWL); capillary_connate_water, the connate water saturation of the capillary pressure only (SWLPC, ISWLPC); connate_gas and capillary_connate_gas, the gas’s (SGL, ISGL; SGLPC, ISGLPC); critical_water and critical_gas, the critical saturations (SWCR, ISWCR; SGCR, ISGCR); critical_oil_to_water and critical_oil_to_gas, the critical oil saturation in water and in gas (SOWCR, ISOWCR; SOGCR, ISOGCR); maximum_water and maximum_gas, the largest saturations (SWU, ISWU; SGU, ISGU); maximum_water_relperm and maximum_gas_relperm, the relative permeabilities at those (KRW, IKRW; KRG, IKRG); oil_relperm_at_connate_water, the oil’s at connate water (KRO, IKRO); gas_relperm_at_residual_oil and water_relperm_at_critical_oil, the gas’s and the water’s at the critical oil saturation (KRGR, IKRGR; KRWR, IKRWR); oil_relperm_at_critical_gas and oil_relperm_at_critical_water, the oil’s at the critical gas and water saturations (KRORG, IKRORG; KRORW, IKRORW); and, for the imbibition curves only, maximum_gas_oil_capillary_pressure and maximum_oil_water_capillary_pressure, the largest capillary pressures (IPCG, IPCW). source notes where the numbers come from (a loaded deck’s card, a paper); the writer does not read it.

Either curve writes ENDSCALE in RUNSPEC, switching end-point scaling on, and its arrays in PROPS. The imbibition curves need a ps.relperm.Hysteresis that names its family, which switches hysteresis on (SATOPTS HYSTER), and a drainage EndpointScaling beside them, which may state no array; without either the model is refused (hysteresis.imbibition.requires_hysteresis_model, hysteresis.imbibition.requires_drainage_baseline). It is stated once, in the list or in saturation region 1’s, at relperm/1/endpoint_scaling (the second stated, drainage and imbibition both, at relperm/1/endpoint_scaling/2).

ps.relperm.Gas(*, sg: NDArray[numpy.float64], krg: NDArray[numpy.float64], pc: NDArray[numpy.float64], source: str | None = None) -> None

Gas relative permeability and capillary pressure against gas saturation (family II).

ps.relperm.Gas(sg=[0.0, 0.8], krg=[0.0, 0.9], pc=[0.0, 0.0]) is a straight gas curve to 0.9 at a gas saturation of 0.8, with no capillary pressure.

Family II states each phase’s curve on its own (SGFN; GSF beside a pc-less water curve in a gas-water system).

Rows: (sg, krg, pc). Each column is a field taking a list, a tuple or a 1-D array, one value per row, None where the simulator derives the cell; Gas.from_frame(frame) reads them from a frame by name.

sg is each row’s gas saturation, krg the gas’s relative permeability and pc the gas capillary pressure there (a pressure, a bare number in the model’s units): the gas-oil one where oil flows, the gas-water one as the storage pair’s GSF. Beside a Water curve that states its pc in a gas-water system, Flow reads the gas-water capillary pressure from that curve’s SWFN and not this one. source notes where the numbers come from (a loaded deck’s card, a paper); the writer does not read it.

It is a statement of ps.Model(relperm=[...]), at relperm/1/gas (saturation region n’s at relperm/<n>/gas in the {region: [...]} form).

ps.relperm.GasOil(*, sg: NDArray[numpy.float64] | None = None, sl: NDArray[numpy.float64] | None = None, krg: NDArray[numpy.float64], krog: NDArray[numpy.float64], pcog: NDArray[numpy.float64], source: str | None = None) -> None

Gas-oil relative permeability and capillary pressure against gas or liquid saturation.

ps.relperm.GasOil(sg=[0.0, 0.8], krg=[0.0, 0.9], krog=[1.0, 0.0], pcog=[0.0, 0.0]) is a pair of straight gas-oil curves, with no capillary pressure.

The saturation column is a choice: sg (gas saturation, SGOF) or sl (liquid saturation, the connate water included, SLGOF); state one.

Rows: (sg or sl, krg, krog, pcog). Each column is a field taking a list, a tuple or a 1-D array, one value per row, None where the simulator derives the cell; GasOil.from_frame(frame) reads them from a frame by name.

krg is the gas’s relative permeability, krog the oil’s in gas (connate water present), and pcog the gas-oil capillary pressure (a pressure, a bare number in the model’s units), at each row’s saturation. source notes where the numbers come from (a loaded deck’s card, a paper); the writer does not read it.

It writes SGOF (SLGOF for sl), one table per saturation region. It is a statement of ps.Model(relperm=[...]), at relperm/1/gas_oil (saturation region n’s at relperm/<n>/gas_oil in the {region: [...]} form).

ps.relperm.GasWater(*, sg: NDArray[numpy.float64], krg: NDArray[numpy.float64], krw: NDArray[numpy.float64], pc: NDArray[numpy.float64], source: str | None = None) -> None

Gas and water relative permeability, gas-water capillary pressure, against gas saturation.

ps.relperm.GasWater(sg=[0.0, 0.8], krg=[0.0, 0.9], krw=[1.0, 0.0], pc=[0.0, 0.0]) is a pair of straight gas-water curves, with no capillary pressure.

The combined gas-water curve (SGWFN).

Rows: (sg, krg, krw, pc). Each column is a field taking a list, a tuple or a 1-D array, one value per row, None where the simulator derives the cell; GasWater.from_frame(frame) reads them from a frame by name.

sg is each row’s gas saturation, krg the gas’s and krw the water’s relative permeability, and pc the gas-water capillary pressure there (a pressure, a bare number in the model’s units). source notes where the numbers come from (a loaded deck’s card, a paper); the writer does not read it.

It writes SGWFN in a gas-water run, one table per saturation region. It is a statement of ps.Model(relperm=[...]), at relperm/1/gas_water (saturation region n’s at relperm/<n>/gas_water in the {region: [...]} form).

ps.relperm.Hysteresis(*, family: Optional[Literal['carlson', 'killough']] = None, scope: Literal['relative_permeability', 'capillary_pressure', 'both'] = 'both', wetting: Literal['saturation_table', 'imbibition_table', 'fully_hysteretic'] = 'imbibition_table', capillary_pressure_scaling: bool = False, capillary_pressure_curvature: float | None = None, wetting_relperm_curvature: float | None = None, cycle_policy: Optional[Literal['alternating_slugs']] = None, lands_parameter: float | None = None, secondary_drainage_reduction: float | None = None, imbibition_linear_fraction: float | None = None, three_phase_switch_threshold: float | None = None) -> None

Relative-permeability hysteresis: the model and the WAG cycles (the whole model).

ps.relperm.Hysteresis(family="killough") turns on Killough’s hysteresis of the relative permeability and the capillary pressure.

family selects the hysteresis model (Carlson or Killough) with its scope and wetting curve. Of the two curvature parameters (positive, dimensionless), capillary_pressure_curvature (EHYSTR item 1) shapes the capillary-pressure scanning curves Flow follows whenever the scope holds the capillary pressure ("both" or "capillary_pressure"); wetting_relperm_curvature (item 3) Flow accepts and does not read, carried because decks state it. cycle_policy and lands_parameter state water-alternating-gas hysteresis, with its optional secondary-drainage reduction, imbibition linear fraction and three-phase switch threshold. A deck may state the WAG cycles without a model (the simulator’s own default then applies), so either half may stand alone. The imbibition curves’ end points are EndpointScaling(curve="imbibition", ...).

It writes SATOPTS HYSTER in RUNSPEC, switching hysteresis on, and EHYSTR for its model and WAGHYSTR for its WAG cycles, in PROPS. It is stated once, in the list or in saturation region 1’s, at relperm/1/hysteresis.

ps.relperm.JFunction(*, phase: Literal['water', 'gas'] = 'water', surface_tension: ScalarPropertyInput, gas_oil_surface_tension: Optional[ScalarPropertyInput] = None, porosity_exponent: Optional[ScalarPropertyInput] = None, permeability_exponent: Optional[ScalarPropertyInput] = None, permeability_basis: Optional[Literal['x_direction', 'horizontal_average', 'y_direction', 'vertical', 'user_defined']] = None) -> None

Leverett J-function capillary-pressure scaling: each cell’s curve by its rock (whole model).

ps.relperm.JFunction(surface_tension=30.0) scales the oil-water capillary pressure of each cell by its porosity and permeability, at a surface tension of 30 dyn/cm.

phase is the phase whose capillary pressure is scaled ("water", the oil-water curve, or "gas", the gas-oil one); surface_tension the oil-water surface tension and gas_oil_surface_tension the gas-oil one, each in dyn/cm whatever the model’s units (as Flow reads JFUNC) and positive; porosity_exponent and permeability_exponent the exponents of porosity and permeability in the scaling (positive), left to the simulator’s default (0.5 each) when unstated; permeability_basis which permeability scales a cell ("x_direction", "y_direction", "vertical" or "horizontal_average", the average of x and y and Flow’s default; "user_defined" writes U, a direction Flow refuses).

It writes JFUNC in GRID and switches end-point scaling on (ENDSCALE). It is stated once, in the list or in saturation region 1’s, at relperm/1/j_function.

ps.relperm.LETRelPerm(*, water=None, oil=None, gas=None, capillary, source: str | None = None) -> None

A phase pair’s relperm and capillary pressure as a LET correlation (one saturation region).

The curves as LET parameters in place of a table, named by phase: the two phases stated are the pair, water and oil (SWOFLET) or gas and oil (SGOFLET); a gas-water pair is refused (it would write SGWFLET, which Flow does not read: state ps.relperm.GasWater). Each curve is a mapping of its parameters: connate_saturation and critical_saturation (saturations, 0 <= connate <= critical < 1), and lower, elevation, top and endpoint_relperm (positive), each 1.0 unless stated. capillary is the pair’s capillary-pressure fit: lower, elevation and top (1.0 unless stated), initial_pressure and threshold_pressure (pressures in the model’s units, not negative, 0.0 unless stated). source says where the parameters came from, as a table’s does. It writes one SWOFLET or SGOFLET record per saturation region and is a statement of ps.Model(relperm=[...]), at relperm/1/let_rel_perm (saturation region n’s at relperm/<n>/let_rel_perm in the {region: [...]} form)::

ps.relperm.LETRelPerm(
water={"connate_saturation": 0.2, "critical_saturation": 0.2, "lower": 2.0},
oil={"connate_saturation": 0.1, "critical_saturation": 0.1},
capillary={"lower": 1.0, "elevation": 1.0, "top": 1.0},
)

ps.relperm.MaxCapillaryPressure(*, maximum_pressure: ScalarPropertyInput) -> None

The largest oil-water capillary pressure the initial water saturation may scale a curve to.

ps.relperm.MaxCapillaryPressure(maximum_pressure=5.0) lets the scaling to the initial water saturation raise a cell’s oil-water capillary pressure to 5 at most.

Where the start states its water saturation cell by cell (ps.initial.Equilibrium(initial_water_saturation=...), SWATINIT), Flow scales each cell’s oil-water capillary pressure to hold it; a cell whose scaled curve would rise above this limit is held at it instead, and its initial water saturation is computed again. One per saturation region: state one in every saturation region, or in none.

maximum_pressure is that pressure (positive, a bare number in the model’s units).

It writes PPCWMAX, one record per saturation region, and switches end-point scaling on (ENDSCALE). It is a statement of ps.Model(relperm=[...]), at relperm/1/max_capillary_pressure (saturation region n’s at relperm/<n>/max_capillary_pressure in the {region: [...]} form).

ps.relperm.Oil(*, so: NDArray[numpy.float64], krow: NDArray[numpy.float64], krog: NDArray[numpy.float64], source: str | None = None) -> None

Oil relative permeability in water and in gas against oil saturation (family II).

ps.relperm.Oil(so=[0.0, 0.8], krow=[0.0, 1.0], krog=[0.0, 1.0]) is the oil’s straight curve in water and in gas, mobile above no oil.

Family II states each phase’s curve on its own: the oil’s for three phases (SOF3). It writes SOF3 wherever oil flows; in an oil-water run Flow reads its family II oil curve from SOF2 instead, which this class does not write.

Rows: (so, krow, krog). Each column is a field taking a list, a tuple or a 1-D array, one value per row, None where the simulator derives the cell; Oil.from_frame(frame) reads them from a frame by name.

so is each row’s oil saturation, krow the oil’s relative permeability in oil and water alone, and krog in oil, gas and connate water. source notes where the numbers come from (a loaded deck’s card, a paper); the writer does not read it.

It is a statement of ps.Model(relperm=[...]), at relperm/1/oil (saturation region n’s at relperm/<n>/oil in the {region: [...]} form).

ps.relperm.OilWater(*, sw: NDArray[numpy.float64], krw: NDArray[numpy.float64], krow: NDArray[numpy.float64], pcow: NDArray[numpy.float64], source: str | None = None) -> None

Oil-water relative permeability and capillary pressure against water saturation.

ps.relperm.OilWater(sw=[0.2, 0.8], krw=[0.0, 0.6], krow=[1.0, 0.0], pcow=[0.0, 0.0]) is a pair of straight oil-water curves from a connate water saturation of 0.2.

Rows: (sw, krw, krow, pcow). Each column is a field taking a list, a tuple or a 1-D array, one value per row, None where the simulator derives the cell; OilWater.from_frame(frame) reads them from a frame by name.

sw is each row’s water saturation; krw the water’s relative permeability, krow the oil’s in water, and pcow the oil-water capillary pressure there (a pressure, a bare number in the model’s units). source notes where the numbers come from (a loaded deck’s card, a paper); the writer does not read it.

It writes SWOF, one table per saturation region. It is a statement of ps.Model(relperm=[...]), at relperm/1/oil_water (saturation region n’s at relperm/<n>/oil_water in the {region: [...]} form).

ps.relperm.SaturationOptions(*, direct: bool = False, irreversible: bool = False, surface_tension: bool = False) -> None

How the saturation-function regions are read (SATOPTS), stated once for the whole model.

ps.relperm.SaturationOptions(direct=True) lets the x, y and z relperm maps each choose the curves of their own direction.

direct=True makes the x, y and z relperm region maps (the regions’ relperm_x, relperm_y and relperm_z) each choose the saturation functions for flow in their own direction: it writes SATOPTS DIRECT in RUNSPEC (beside HYSTER when the model states hysteresis). irreversible and surface_tension are refused by the checks (regions.saturation_options.irreversible_unsupported, regions.saturation_options.surface_tension_unsupported): OPM Flow supports neither.

It is stated in the list or in saturation region 1’s, at relperm/1/saturation_options.

ps.relperm.ThreePhase(*, method: Literal['stone1', 'stone2'], exponent: Optional[ScalarPropertyInput] = None, source: str | None = None) -> None

The three-phase method: how the oil’s relative permeability comes from its two-phase curves.

ps.relperm.ThreePhase(method="stone2") takes the oil’s three-phase relative permeability by Stone’s second method.

Stone’s first method ("stone1", STONE1) or his second ("stone2", STONE2), in any case; a model that states none takes the simulator’s default. A saturation region’s statement: in the {region: [...]} form every region states it, all with one method. exponent is Stone I’s exponent for the region (STONE1EX, dimensionless and positive), stated in every region or in none, and only with "stone1".

method is the method’s word. source notes where the numbers come from (a loaded deck’s card, a paper); the writer does not read it.

It is a statement of ps.Model(relperm=[...]), at relperm/1/three_phase (saturation region n’s at relperm/<n>/three_phase in the {region: [...]} form).

ps.relperm.Water(*, sw: NDArray[numpy.float64], krw: NDArray[numpy.float64], pc: NDArray[numpy.float64] | None = None, source: str | None = None) -> None

Water relative permeability and capillary pressure against water saturation (family II).

ps.relperm.Water(sw=[0.2, 1.0], krw=[0.0, 1.0]) is a straight water curve from a connate saturation of 0.2.

Family II states each phase’s curve on its own (SWFN). Without pc, in a gas-water system the curve is the storage system’s water curve (WSF), beside its gas curve; elsewhere it writes SWFN with pc 0.

Rows: (sw, krw, pc). Each column is a field taking a list, a tuple or a 1-D array, one value per row, None where the simulator derives the cell; Water.from_frame(frame) reads them from a frame by name.

sw is each row’s water saturation, krw the water’s relative permeability and pc the oil-water capillary pressure there, or in a gas-water system the gas-water one, which Flow reads from this curve beside an SGFN gas curve (a pressure, a bare number in the model’s units). source notes where the numbers come from (a loaded deck’s card, a paper); the writer does not read it.

It is a statement of ps.Model(relperm=[...]), at relperm/1/water (saturation region n’s at relperm/<n>/water in the {region: [...]} form).

PetroScript is licensed under the Apache License 2.0. © 2026 Blauweiss EDV LLC. PetroScript by Blauweiss AI.For AI agents: llms.txt