Well identities and groups
The PetroScript well model is split across three semantic objects:
ps.Well— a well’s identity: its name, its head column and its group. Whether it produces or injects is the control a dated change gives it.ps.Group— an operating group, in the model’sgroups=.ps.Perforate— a dated connection between a wellbore and a run of layers in one grid column.
For scheduled controls (ps.Produce(...), ps.Shut(...),
ps.wells.Regroup(...), ps.Schedule(...), etc.) see
wells-schedule.md. This page focuses on the
well/group/completion shapes themselves.
Group handles
Section titled “Group handles”A well’s group is a ps.Group, and the model’s groups= declares every group
its wells and policies name. Reuse the same group values when building wells and
scheduling group policies:
import petroscript as ps
field_group = ps.Group(name="FIELD")operating_group = ps.Group(name="OP1", parent=field_group)
prod = ps.Well(name="PROD1", i=10, j=10, group=operating_group)start = ps.Event( "2020-01-01", ps.Perforate(well="PROD1", k=(3, 3), diameter=0.5), ps.Produce(well="PROD1", oil_rate=20_000.0, bhp_limit=1000.0), ps.wells.Regroup(well=prod, group=operating_group.name),)Group is a frozen pydantic value object with two fields: name: str and
parent: Group | None. Two distinct Group instances with the same name and
parent compare equal, so validation can compare handles safely whether or not
the same Python object was reused.
Well.group: Group | None = None — passing None is valid for cases that have no group structure.
bhp_reference_depth is optional on ps.Well. When it is omitted the
render DEFAULTS WELSPECS item 5 — it emits 1* and lets OPM Flow derive the
BHP datum from the mid-point of the shallowest connection. Pass
bhp_reference_depth=... only when the problem statement gives a deliberate
datum.
PetroScript does not write that mid-point itself, even where the grid family makes it computable: stating the same value does not say the same thing. On two FIELD decks the lowered depth is correct to every digit the restart file prints and the runs still diverge, because a stated depth crosses the unit conversion as one multiplication while the target accumulates its own in SI from converted grid geometry. A value the target would derive is not ours to state; agreement to every printed digit is not agreement.
The model still knows the depth — the physics guards ask for it, and the warning about a datum far from the grid reads it. Only the deck leaves it unstated.
Completion factors
Section titled “Completion factors”ps.Perforate(...) states a connection’s semantics. A missing connection factor
or skin factor means “use the simulator default”; the lowerer owns any
deck-token representation. Beside the interval and the diameter it takes the
connection factor, kh, the skin factor, the non-Darcy factor, the direction
and the saturation region when the problem states them:
perforation = ps.Perforate(well="PROD1", k=(1, 1), diameter=0.5, skin_factor=2.0)Well dimensions
Section titled “Well dimensions”Well-dimension limits are semantic capacity metadata. The compiler sizes
ordinary well and group capacity from the wells and groups the model declares;
ps.Model(capacity=ps.Capacity(wells=..., connections_per_well=..., ...))
states a larger allocation when a scenario needs one, by name rather than as a
raw positional tuple.
Typed well controls, status, and phase
Section titled “Typed well controls, status, and phase”Core wellbore authoring is typed. Users should not memorize or pass simulator control/status/phase tokens; each choice is a field with listed words:
ps.Produce(well=..., oil_rate=..., ...)andps.Inject(well=..., phase=..., rate=..., ...)name control intent without spelling backend control tokens.ps.Open,ps.Shutandps.Stopchange lifecycle state; a control’sstatusis"open","shut"or"stop".- An injector’s
phase, and a well’spreferred_phase, is"oil","water"or"gas". - A group control is
control="group", a well test’sreasonsare among"physical","economic"and"group_economic", a workover’s scope isworkover_scope=onps.wells.Economics, a guide rate’sphaseis one of its listed words, and the injection multiplier and damage policies take theirreversibilityandgeometrythe same way.
A word outside a field’s choices is refused at construction, and a numeric string is refused where a number is expected. The compiler owns the eventual deck token mapping.
PetroScript is licensed under the Apache License 2.0. © 2026 Blauweiss EDV LLC. PetroScript by Blauweiss AI.For AI agents: llms.txt