Skip to content

Rock compaction

PetroScript models rock compaction as reservoir concepts. Pressure-dependent compaction attaches per-region multiplier tables to the rock fabric; the water-induced family attaches pore-volume (loading) and transmissibility (unloading) multiplier tables with saturation nodes and overburden curves. Compiler lowerers own the ECL/Flow keywords (ROCKCOMP, ROCKOPTS, ROCKTAB, ROCK2D, ROCK2DTR, ROCKWNOD, and OVERBURD).

State ps.grid.RockPressureCompaction(...) as the rock’s compaction= when building a model from semantic primitives. This example allocates two multiplier tables by rock regions:

import numpy as np
import petroscript as ps
compaction = ps.grid.RockPressureCompaction(
tables=[
[[2000.0, 0.96, 0.965], [3000.0, 0.99, 0.995], [4500.0, 1.0, 1.0]],
[[2000.0, 0.95, 0.955], [3000.0, 0.98, 0.985], [4500.0, 1.0, 1.0]],
],
table_regions="rock_regions",
)
field = ps.Group(name="FIELD")
model = ps.Model(
name="COMPACTION_CASE",
units="field",
start="2020-01-01",
grid=ps.grid.Cartesian(shape=(2, 2, 1), dx=500.0, dy=500.0, dz=40.0, top=2500.0),
rock=ps.Rock(porosity=0.25, permeability=100.0, vertical_ratio=1.0, compaction=compaction),
regions=ps.Regions(rock=np.array([[[1], [1]], [[2], [2]]])),
fluid=ps.fluid.OilWater(
oil=ps.pvt.DeadOil(pressure=[14.7, 3500.0], oil_fvf=[1.06, 1.0], oil_viscosity=[1.0, 1.2]),
water=ps.pvt.Water(
reference_pressure=3000.0,
fvf=1.0,
compressibility=3.0e-6,
viscosity=0.5,
viscosibility=0.0,
),
oil_surface_density=53.0,
water_surface_density=64.0,
),
relperm=[ps.relperm.OilWater(sw=[0.20, 0.80], krw=[0.0, 1.0], krow=[1.0, 0.0], pcow=[0.0, 0.0])],
initial=ps.initial.Equilibrium(
datum_depth=2510.0, datum_pressure=3000.0, oil_water_contact=2600.0, gas_oil_contact=0.0
),
groups=[field],
wells=[
ps.Well(name="PROD1", i=2, j=2, group=field),
ps.Well(name="INJ1", i=1, j=1, group=field),
],
schedule=ps.Schedule(
report=[ps.Every(30.0)],
events=[
ps.Event(
"2020-01-01",
ps.Perforate(well="PROD1", k=(1, 1), diameter=0.3),
ps.Perforate(well="INJ1", k=(1, 1), diameter=0.3),
ps.Produce(well="PROD1", oil_rate=150.0, bhp_limit=2500.0),
ps.Inject(well="INJ1", phase="water", rate=300.0, bhp_limit=4500.0),
)
],
),
)

Each table row is (pressure, pore_volume_multiplier, transmissibility_multiplier) for one rock region; pressures increase strictly down the rows, and multipliers are positive and equal or increasing. The compiler declares the compaction run (ROCKCOMP), the table allocation options (ROCKOPTS), the table dimensions, and the tables themselves (ROCKTAB).

reversibility= selects whether pore volume recovers when pressure builds back up:

irreversible = ps.grid.RockPressureCompaction(
tables=[[[2000.0, 0.96, 0.965], [4500.0, 1.0, 1.0]]],
reversibility="irreversible",
)

"reversible" and "irreversible" are the only choices: OPM Flow rejects the hysteretic (HYSTER, BOBERG) compaction modes natively, so they are not part of the semantic surface.

  • store_initial_pressure=True references the multipliers at the initial grid-block pressures instead of the tabulated reference pressures.
  • table_regions chooses the region family that allocates tables to cells: "pvt_regions" (the default) or "rock_regions". Rock-region allocation requires a rock region map (ps.Regions(rock=...)); a model without one fails with issue code rock.compaction.table_regions.rock_map_missing.

Bad table values fail with structured issue codes rock.compaction.tables.row_count, rock.compaction.tables.pressure_order, and rock.compaction.tables.multiplier_range.

The water-induced family remains available through ps.grid.RockCompaction with water_induced=True, pore-volume (loading) and transmissibility (unloading) multiplier tables, water saturation nodes, and overburden curves. The overburden-stress tabulation mode of the pressure tables (STRESS) is not exposed: OPM Flow rejects it natively.

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