ps.actions
ps.actions.PyAction
Section titled “ps.actions.PyAction”ps.actions.PyAction(name: str, path: str = '', run_mode: PythonHookRunModeChoice = 'once', script: str | None = None) -> None
A Python hook the run calls: ps.actions.PyAction(name="WTEST", path="wtest.py").
name names the hook (PYACTION record 1, item 1: upper-case letters, digits and
_+.-, starting with a letter); path is the Python file Flow runs, read from the
deck’s folder (record 2, written as a quoted word: Flow gives it no default, so a hook
stating none is refused); run_mode
is how often it runs: "once", "every_timestep" or "until_true" (record 1,
item 2: SINGLE, UNLIMITED, FIRST_TRUE; an unwritten one is SINGLE); script is the
file’s text, written beside the deck as path (ps.load reads it when the deck’s folder
holds it as UTF-8 text; None holds no file, and the run’s folder must then hold it; a script
written over the deck, or over another hook’s other script, is refused). Stated in
ps.Event(date, ...), as a ps.actions.When is, and written there; its address is
schedule/<date>/py_action. PetroScript never imports, evaluates or runs the file.
ps.actions.UserQuantity
Section titled “ps.actions.UserQuantity”ps.actions.UserQuantity(*, name: str, statements, units: str | None = None, stated_units_position: int | None = None) -> None
A user quantity (UDQ): a name the run evaluates from a formula or a number.
ps.actions.UserQuantity(name="FU_CAP", expression=ps.actions.field().oil_production_rate.minimum(1000.0)) is the field’s oil rate
capped at 1000, a quantity a rule’s condition or a control may read. Its formula reads
every member of its own scope (every well of a WU…, every group of a GU…) or one value,
as Flow does: a field quantity names its group (ps.actions.group(ps.Group(name="FIELD"))),
and Flow evaluates field, group, well and segment quantities only.
expression= states one formula (a number is a constant); statements= states each
record in order instead: a value for some wells or groups ({"expression": 4.0, "well": "PROD"}, written ASSIGN) or a switch of the name’s evaluation ({"evaluated": False},
written UPDATE). The quantity is itself an expression: a formula, a rule’s condition or a
control’s rate reads it by its name. It is stated in ps.Event(date, ...) and written
there in a UDQ card (DEFINE, ASSIGN, UPDATE, UNITS); its address is
schedule/<date>/user_quantity.
ps.actions.UserTable
Section titled “ps.actions.UserTable”ps.actions.UserTable(name: str, interpolation: InterpolationModeChoice, x: tuple[float, ...] | ColumnIn, y: tuple[float, ...] | ColumnIn) -> None
A user table (UDT): a one-dimensional lookup a user quantity’s formula reads.
ps.actions.UserTable(name="TU_FBHP", interpolation="linear_clamped", x=(100.0, 500.0), y=(100.0, 180.0)) reads 100 at argument 100 and 180 at 500, a straight line between and the
end values beyond.
name is the table’s name, which a user quantity’s formula looks it up by
(table.lookup(x), written TU_FBHP[x]): Flow evaluates a lookup only of a name that
starts with TU_, and the constructor does not check the prefix. A name that starts with
TU but no underscore loads, then aborts the run when Flow evaluates the quantity that reads
it. x holds the argument values and y the value at each; Flow refuses a table whose
arguments do not rise strictly, which the constructor does not check either.
interpolation is how a value is read: "linear_clamped" (a straight line between
points, the end values beyond), "linear_extrapolated" (the end lines carried on beyond)
or "nearest" (the nearer point’s value). A table is stated in the schedule’s first
ps.Event and written at the deck’s head; a later date is refused
(schedule.event.start_only). Its address is schedule/<start>/user_table.
ps.actions.When
Section titled “ps.actions.When”ps.actions.When(*conditions: Expression, name: str, condition: Expression, then: tuple[Flux | Output | Numerics | Efficiency | Well | Adjust | Regroup | History | InjectionHistory | ControlDefaults | HistoryControl | Open | Shut | Stop | Perforate | Scale | FaultMultiplier | VaporizationControls | WellTest | Economics | Economics | GuideRate | ProductivityIndex | ProductivityMultiplier | TargetMultiplier | InjectionMultiplier | InjectionDamage | InjectedStream | FilterCake | WellList | PressureAveraging | Survey | DamageFactorCorrection | Cycling | NonDarcyFactor | Produce | Inject | Group | ProductionTarget | InjectionTarget | GuideRates | PressureMaintenance | GasSales | FuelGas | Satellite | Branch | Node | Efficiency | SourceTerm | BoundaryCondition | When | DissolutionLimits | ConvectiveDissolution | PyAction | UserTable | UserQuantity | Segments | Valve | ICD | AICD | Lump | Skin | GasLiftOptimization | GasLift, ...], runs: int | None = None, minimum_wait: Optional[ScalarPropertyInput] = None, stated_body_scopes: tuple[tuple[str, int, tuple[int | None, ...] | None], ...] = (), stated_body_cards: tuple[tuple[str, int, int], ...] = ()) -> None
An operating rule (ACTIONX): when its conditions hold, its changes apply.
ps.actions.When(*conditions, then=[...], name=, runs=, minimum_wait=): the conditions are
expressions over the run’s quantities (ps.actions.well(p1).water_cut > 0.85,
ps.actions.date() >= "2026-03-01"), all of which must hold; then lists the changes,
which may name the wells whose condition fired as well="?"; runs is how many times
the rule may fire. A rule acting on "?" over every well must state runs: the
simulator fires a rule once by default, so only the first well to cross would change.
name is the rule’s name: upper-case letters, digits, _ and -, a letter first, up
to 32 characters, and never SKIP, SKIP100, SKIP300 or ENDSKIP. minimum_wait is the least
time between two firings: a number of days in every unit system, or a ps.Quantity in
"day", "hr" or "s" ("hour" or "days" passes here and is refused when
the model is compiled). The rule is stated in ps.Event(date, ...) (or m.at(date, ...))
and written there, its changes between ACTIONX and ENDACTIO; its address is
schedule/<date>/actions/<name>.
A rule is itself a schedule event and stands where the deck states it. Position is not a formatting choice: measured on both supported releases, a rule stated before further dated groups gives a different run from the same rule moved after the last one, and the moved run is byte-identical in its restart state to a run with no rule at all — the restart carries the rule definitions, and moving a rule past the last dated group leaves the run’s own record of itself with none. Rendering every rule at the end of the schedule is therefore a deletion that leaves the card visible, which is why the rule joins the event stream instead of a collection beside it.
A rule restated by name replaces the earlier rule of that name from where it stands, its firings counted afresh, as Flow does (opm-common Actions::add: the same slot, a new id the run count is kept by): model4/MOD4_UDQ_ACTIONX restates ACT01 and ACT01A at later dates.
ps.actions.date
Section titled “ps.actions.date”ps.actions.date() -> Clock
The simulation date, compared with a date in a condition (YEAR, MNTH and DAY).
ps.actions.date() >= "2026-03-01" holds from that date on.
Returns
Section titled “Returns”Clock
The date, compared with a day (its text 'YYYY-MM-DD' or a datetime.date) by
==, <, <=, > and >=, or read by its terms .year, .month and
.day, each compared with a number (a month also with its word).
ps.actions.field
Section titled “ps.actions.field”ps.actions.field() -> Quantities
The field’s quantities, as a rule’s condition or a user quantity’s formula reads them.
ps.actions.field().oil_production_rate < 500.0 holds while the field produces less than 500.
Returns
Section titled “Returns”Quantities
The field’s quantities, each an attribute by its long name (.oil_production_rate,
.pressure; dir() lists them), compared with a number in the model’s units or
combined into a formula.
ps.actions.group
Section titled “ps.actions.group”ps.actions.group(group: Any = None) -> Quantities
The quantities of group (a ps.Group), or of every group when none is named.
Every group is read in a user quantity’s formula only; a rule’s condition names its group (Flow has no every-group condition).
ps.actions.group(north).water_cut > 0.9 holds while the water cut of north is above 0.9.
Parameters
Section titled “Parameters”group : ps.Group, optional
The group whose quantities are read: its handle (m.get("groups/NORTH")), never its
name. None reads every group’s in a user quantity’s formula; Flow reads a group’s
quantity in a rule’s condition for a named group only, so a condition names its group.
Returns
Section titled “Returns”Quantities
The group’s quantities, each an attribute by its long name (.water_cut,
.oil_production_rate; dir() lists them), compared with a number in the model’s
units or combined into a formula.
Raises
Section titled “Raises”TypeError
When group is a name, or anything else that is not a ps.Group.
ps.actions.region
Section titled “ps.actions.region”ps.actions.region(region: int, *, fluid_in_place_set: str | None = None) -> Quantities
The quantities of fluid-in-place region region: ps.actions.region(2).oil_in_place.
region is the region’s number (one or more) in the model’s fluid-in-place regions, or in
the set fluid_in_place_set names (a key of ps.Regions(fluid_in_place_sets=), the three
characters its vectors carry).
Parameters
Section titled “Parameters”region : int
The region’s number, 1 or more.
fluid_in_place_set : str, optional
The fluid-in-place set the number counts in, a key of
ps.Regions(fluid_in_place_sets=); None counts in the model’s own fluid-in-place
regions.
Returns
Section titled “Returns”Quantities
The region’s quantities, each an attribute by its long name (.oil_in_place,
.pressure; dir() lists them), compared with a number in the model’s units or
combined into a formula.
Raises
Section titled “Raises”ValueError
When region is not a whole number of 1 or more.
ps.actions.well
Section titled “ps.actions.well”ps.actions.well(well: Any = None, *, lists: str | None = None) -> Quantities
The quantities of well (a ps.Well), of a set of wells, or of every well.
ps.actions.well().water_cut > 0.85 holds for each well whose water cut passes 0.85, which a
rule’s changes name as well="?". A condition reads a set of wells on a comparison’s left
side (Flow reads a list of wells there only), and the set may be narrowed: a string is a
pattern over WELL names (ps.actions.well("OP0*"), ps.actions.well("*RO*"): * any
run, ? one character), a ps.wells.WellList reads the wells of that declared list, and
lists= reads the wells of every declared list whose name matches (lists="PR*") or of
one list by its name (lists="NORTH"). A pattern and a list are matched at each check,
against the wells and lists that stand then.
Parameters
Section titled “Parameters”well : ps.Well, str or ps.wells.WellList, optional
The well whose quantities are read, by its handle (m.get("wells/P1")); a pattern over
well names; or a declared list. None reads every well’s: a rule’s condition writes the
quantity over '*' (WWCT '*' > 0.85).
lists : str, optional
A list’s name or a pattern over list names, in place of well.
Returns
Section titled “Returns”Quantities
The well’s quantities, each an attribute by its long name (.water_cut,
.bottom_hole_pressure; dir() lists them, and a name it does not list is an
AttributeError naming the nearest), compared with a number in the model’s units
or combined into a formula.
Raises
Section titled “Raises”TypeError
When well is one well’s name (its handle reads it), or none of the kinds above.
ValueError
When well and lists are both given, or a pattern is not one.
PetroScript is licensed under the Apache License 2.0. © 2026 Blauweiss EDV LLC. PetroScript by Blauweiss AI.For AI agents: llms.txt