Relative permeability and SCAL
Reservoir meaning
Section titled “Reservoir meaning”Relative permeability tables describe how phase mobility changes as saturation changes. A phase may be present in a cell but still flow poorly if its relative permeability is low. Capillary pressure columns describe pressure offsets between phase pairs where the model uses them.
PetroScript API
Section titled “PetroScript API”Each saturation curve is a ps.relperm table held by column (one saturation
region), its columns the literature’s symbols in the literature’s order, each
pair of phases named lighter phase first. A cell the deck defaults is None
(the simulator derives it, written 1*); the saturation column states every
row. from_frame reads a curve’s columns by name from a polars or pandas
frame, or a mapping of column name to values.
import petroscript as ps
water_oil = ps.relperm.OilWater(sw=[0.2, 0.8], krw=[0.0, 1.0], krow=[1.0, 0.0], pcow=[0.0, 0.0])gas_oil = ps.relperm.GasOil.from_frame( {"sg": [0.0, 0.8], "krg": [0.0, 1.0], "krog": [1.0, 0.0], "pcog": [0.0, 0.0]})OilWater
Section titled “OilWater”ps.relperm.OilWater has the columns sw, krw, krow and pcow. It
describes water-oil flow behavior as water saturation varies.
GasOil
Section titled “GasOil”ps.relperm.GasOil has the columns sg (or sl), krg, krog and pcog. It
describes gas-oil flow behavior as gas saturation varies; stated against the
liquid saturation sl instead, it is the SLGOF-style gas/oil table where liquid
saturation, rather than gas saturation, indexes the gas/oil mobility
relationship.
Family II phase tables
Section titled “Family II phase tables”ps.relperm.Water, ps.relperm.Gas and ps.relperm.Oil model split
phase-function tables. They are useful when a deck expresses water, gas, and
oil mobility as separate functions rather than paired water/oil and gas/oil
tables. PetroScript keeps these as semantic phase-function tables; users do not
author target keyword records directly.
Water has columns sw, krw and pc. Gas has columns sg, krg and
pc. Oil has columns so, krow and krog. In a gas-water system a
Water curve without pc is the storage system’s water curve, beside its Gas
curve; elsewhere it states
no capillary pressure. ps.relperm.GasWater has the columns sg, krg, krw
and pc.
The relperm list
Section titled “The relperm list”A model’s relperm is the list of its saturation functions and the statements
about them, or one list per saturation region as {region: [...]}.
Use paired tables such as ps.relperm.OilWater and ps.relperm.GasOil for
classic SPE-style water/oil and gas/oil behavior. Use ps.relperm.Water,
Gas, and Oil for split family II phase functions. Use either an sg or an
sl gas/oil curve for one gas/oil relperm family, not both.
Statements that hold for the whole model sit in the same list (or region 1’s):
ps.relperm.JFunction(phase, surface tension, …) enables bounded J-function capillary pressure behavior.ps.relperm.MaxCapillaryPressure(maximum pressure) applies a positive water capillary-pressure maximum, one per saturation region.ps.relperm.CriticalTolerance(value) is the relative permeability at or below which a phase counts as immobile when critical saturations are found.ps.relperm.Hysteresis(family="killough" | "carlson", ...)selects a typed hysteresis model, scope, wetting policy, and capillary-pressure scaling behavior.ps.relperm.EndpointScaling(curve="imbibition", ...)describes imbibition endpoint maps with semantic field names such asconnate_water,maximum_gas_relperm,oil_relperm_at_critical_water, andmaximum_oil_water_capillary_pressure.ps.relperm.Hysteresis(cycle_policy="alternating_slugs", ...)enables typed WAG hysteresis with only Flow-supported controls: Land’s parameter, secondary drainage reduction, imbibition linear fraction, and three-phase switch threshold.
The three-phase method, ps.relperm.ThreePhase with method="stone1" or
"stone2", sits in every saturation region’s list with one method; a Stone-I
exponent is stated in every region or in none.
These controls are semantic API objects; users do not author backend keyword records directly.
Hysteresis controls
Section titled “Hysteresis controls”Hysteresis controls are statements in the relperm list, so the public API describes behavior rather than deck cards:
hysteresis = ps.relperm.Hysteresis( family="killough", scope="both", wetting="imbibition_table", capillary_pressure_scaling=True, cycle_policy="alternating_slugs", lands_parameter=3.0, secondary_drainage_reduction=0.5, imbibition_linear_fraction=0.2, three_phase_switch_threshold=0.01,)imbibition = ps.relperm.EndpointScaling( curve="imbibition", connate_water=0.16, maximum_water=0.82, maximum_gas=0.77, maximum_water_relperm=0.66, maximum_gas_relperm=0.71, oil_relperm_at_critical_water=0.62, maximum_oil_water_capillary_pressure=20.0,)drainage = ps.relperm.EndpointScaling( method="three_point", connate_water=0.18, maximum_water=0.85, maximum_gas=0.80,)relperm = [ ps.relperm.Water(sw=[0.16, 0.82], krw=[0.0, 0.66], pc=[0.0, 0.0]), ps.relperm.Gas(sg=[0.0, 0.77], krg=[0.0, 0.71], pc=[0.0, 0.0]), ps.relperm.Oil(so=[0.0, 0.84], krow=[0.0, 1.0], krog=[0.0, 1.0]), drainage, imbibition, hysteresis,]A word-valued choice takes one of its listed words in lower case or in capitals; a word naming none, a mixed case included, is refused listing the choices. This keeps tests and agent-authored PetroScript focused on reservoir semantics such as typed hysteresis model selection, imbibition endpoint maps, or alternating WAG slugs, while the compiler owns the exact backend records.
Units and shapes
Section titled “Units and shapes”Paired relperm tables have four columns, split phase-function tables three,
each column one value per row. Saturations and relative permeabilities are unitless. Capillary
pressure is in the model pressure unit system; under FIELD, that is psi. Each
column is a list, a tuple or a 1-D array of finite numbers (None for a
defaulted cell); numeric strings, object arrays and booleans are rejected
instead of coerced.
Validation and common mistakes
Section titled “Validation and common mistakes”Saturation columns should be monotonic, bounded to physically meaningful values, and should not skip endpoints that the simulator needs for interpolation. Relative permeabilities should be non-negative. Common mistakes are reversing water/gas saturation columns, using percentages instead of fractions, and assuming a capillary-pressure value is unitless.
Lowers to
Section titled “Lowers to”Current status: emitted now for the implemented single-region SCAL-style path.
SWOFis emitted fromOilWater.SGOFis emitted fromGasOil, andSLGOFfrom aGasOilstated againstsl.SWFN,SGFN, andSOF3are emitted from split phase-function tables (aWatercurve withoutpcwritesSWFNwithpc0), andGSF/WSFfrom a gas-water storage system’s pair.
J-function capillary pressure, water capillary-pressure maxima, the Stone I and II three-phase methods, the critical-saturation tolerance, endpoint hysteresis, WAG hysteresis, solvent saturation/PVT properties, and directional relperm family maps are emitted now through the semantic controls above. Broader capillary-pressure systems and family-specific solvent saturation functions remain future/unsupported.
Imbibition regions, undirected and directional
Section titled “Imbibition regions, undirected and directional”regions.imbibition assigns one imbibition region per cell, applying in every
flow direction, and lowers to IMBNUM. A run whose imbibition regions differ
by direction states regions.imbibition_x, imbibition_y and imbibition_z
instead, three plain maps like the relative-permeability triple’s relperm_x,
relperm_y and relperm_z, and they lower to IMBNUMX, IMBNUMY and
IMBNUMZ. A deck may state both, and the corpus does.
The directional triple obeys the two rules its relperm sibling obeys, for the
same reasons: all three directions or none, because a direction left out has
no map to fall back on; and SaturationOptions(direct=True) (SATOPTS 'DIRECT', a model-wide item of the relperm list), because that is what turns
directional regions on at all.
The LET correlation family
Section titled “The LET correlation family”A saturation function can be stated as a fitted correlation instead of a table.
ps.relperm.LETRelPerm states one, from two per-phase curves (water and oil
for the water-oil pair, gas and oil for the gas-oil pair) and one
capillary-pressure fit, each a mapping of its named parameters: it sits in the
relperm list, one per saturation region, exactly as tabulated curves do.
water_oil_let = ps.relperm.LETRelPerm( water={ "connate_saturation": 0.021, "critical_saturation": 0.021, "lower": 1.927, "elevation": 5.667, "top": 2.214, "endpoint_relperm": 0.995, }, oil={ "connate_saturation": 0.021, "critical_saturation": 0.100, "lower": 2.367, "elevation": 3.100, "top": 1.900, "endpoint_relperm": 1.002, }, capillary={ "lower": 1.0, "elevation": 1.0, "top": 1.0, "initial_pressure": 0.0, "threshold_pressure": 0.0, },)A LET model and a tabulated table for the same phase pair are mutually
exclusive; stating both reports relperm.let.excludes_tabulated.
SWOFLET and SGOFLET are emitted from these correlations, and importing a deck
that states them reads them back: seventeen parameters per saturation region,
in the deck’s own order and with the deck’s own numbers. Every one must be
stated. A tabulated family reads a defaulted cell off the simulator’s own
derivation, but each LET parameter shapes the curve on its own and there is no
neighbouring row to read a missing one from, so a defaulted slot is reported
rather than filled in with a number the deck did not choose.
The endpoint relative permeability must be positive and is not capped at one.
The textbook range would cap it, and the corpus contradicts that: model2’s
LET include states Krto = 1.002 in eight of its ten water-oil tables and
Krtg = 1.005 in all ten of the gas-oil set, and the target runs that deck.
Drainage endpoint scaling
Section titled “Drainage endpoint scaling”Use ps.relperm.EndpointScaling(...) (its curve is "drainage" unless stated) to describe drainage endpoint-scaling intent. The API uses semantic field names such as connate_water, capillary_connate_water, critical_water, maximum_water_relperm, and oil_relperm_at_critical_gas. Backend endpoint arrays and scaling-option cards are compiler-owned; users should not author raw endpoint keyword calls.
Example:
endpoints = ps.relperm.EndpointScaling( method="three_point", connate_water=0.18, capillary_connate_water=0.19, connate_gas=0.02, capillary_connate_gas=0.03, critical_water=0.24, critical_gas=0.05, maximum_water=0.85, maximum_gas=0.80, maximum_water_relperm=0.70, maximum_gas_relperm=0.75, gas_relperm_at_residual_oil=0.55, water_relperm_at_critical_oil=0.50, oil_relperm_at_critical_gas=0.62, oil_relperm_at_critical_water=0.64,)relperm = [water_oil, gas_oil, endpoints]Every relative-permeability anchor may be stated under either method. SCALECRS
item 1 chooses how the saturations scale (two-point by default); the anchors
KRGR, KRWR, KRORG and KRORW switch Flow’s three-point scaling of the
relative-permeability value on by being stated (opm-common EclEpsConfig), and
a two-point run with gas_relperm_at_residual_oil is another run than one
without it. The imbibition anchors (IKRGR and the like) follow the same rule.
SCALECRS is not a user-facing authoring surface; it is emitted internally only when typed scaling policy requires it. Imbibition endpoint maps are authored through ps.relperm.EndpointScaling(curve="imbibition", ...) when hysteresis is active.
PetroScript is licensed under the Apache License 2.0. © 2026 Blauweiss EDV LLC. PetroScript by Blauweiss AI.For AI agents: llms.txt