Skip to content

Multisegment wellbores

A multisegment wellbore divides a well’s flow path into numbered segments so the simulator resolves pressure and holdup along the tubing and through completion devices. PetroScript models this with ps.wells.Segments: its segments rows describe the segment tree below the top segment, each flowing into its parent, and its connections rows place the well’s perforated cells on a branch. Typed device objects (ps.wells.Valve, ps.wells.ICD, ps.wells.AICD) describe flow control hardware on individual segments, each naming its well and the segment’s number. Each is a change a ps.Event dates. The compiler owns all simulator keyword layouts and the multisegment dimension bookkeeping.

Authoring a segmented producer with an autonomous ICD

Section titled “Authoring a segmented producer with an autonomous ICD”

An autonomous inflow-control device (AICD) chokes back high-mobility fluids (water, gas) by making its pressure drop depend on the flowing mixture’s density and viscosity. The device is ps.wells.AICD, and the mixture is characterized per phase: the oil/water/gas flowing-fraction exponents of the density and viscosity mixture laws are mappings by phase ({"oil": 1.1, "water": 1.2, "gas": 1.3}), and the overall density exponent of the pressure-drop law is density_exponent.

import petroscript as ps
group = ps.Group(name="FIELD")
segments = ps.wells.Segments(
well="PROD1",
top_depth=2510.0,
segments=[
{"number": 2, "branch": 1, "parent": 1, "length": 50.0, "depth": 0.0,
"diameter": 0.152, "roughness": 1.0e-5},
{"number": 3, "branch": 2, "parent": 2, "length": 0.1, "depth": 0.0,
"diameter": 0.152, "roughness": 1.0e-5},
],
connections=[
{"i": 2, "j": 2, "k": 1, "branch": 2, "start_length": 0.0, "end_length": 0.1},
],
)
device = ps.wells.AICD(
well="PROD1",
segment=3,
strength=7.5e-5,
length=-0.028975,
calibration_density=1020.0,
calibration_viscosity=0.48,
emulsion_critical_fraction=0.7,
flow_rate_exponent=2.2,
viscosity_exponent=0.5,
density_mixture_exponents={"oil": 1.1, "water": 1.2, "gas": 1.3},
viscosity_mixture_exponents={"oil": 0.7, "water": 0.8, "gas": 0.9},
density_exponent=0.75,
)
model = ps.Model(
name="SEGMENTED_PRODUCER",
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),
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=[group],
wells=[
ps.Well(name="PROD1", i=2, j=2, group=group),
ps.Well(name="INJ1", i=1, j=1, group=group),
],
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),
segments,
device,
)
],
),
)

The mixture-exponent arguments are optional and AICD-specific: spiral ICDs (ps.wells.ICD) and segment valves do not accept them, and a device without them emits the same short record as before. A mixture law states all three phases’ exponents (1.0 is the neutral one); density_exponent must be non-negative.

Segment geometry is expressed on each segments row (length, depth change, diameter, roughness, and where they are not the pipe’s own, cross_section_area and volume) and on ps.wells.Segments itself (top_depth, top_length, top_volume, the incremental-vs-absolute length_depth_mode, and the hydrostatic/friction/acceleration pressure_drop_model). A connections row may also state the direction the connection penetrates its cell (direction, "x", "y" or "z"), the last cell of a range along it (end_range), the depth its pressure is referred to (depth), its thermal_length, and the number of the segment it joins (segment; left out, OPM Flow joins it to its branch’s segment nearest it). Adding "direction": "z", "depth": 2510.0, "segment": 3 to the row above writes 2 2 1 2 0 0.1 Z 1* 2510 1* 3 / under COMPSEGS. The remaining simulator-side wellbore columns are not part of the semantic surface because OPM Flow does not support them:

  • the drift-flux multiphase segment model (only the homogeneous default runs),
  • display coordinates and pipe-wall thermal columns on the segment records,
  • chord-link dimensioning (the simulator ignores it; the compiler leaves the slot defaulted).

The compiler computes multisegment dimensions from the authored segment trees; ps.Capacity(multisegment_wells=..., segments_per_well=..., branches_per_well=...) reserves more than the model holds.

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