ps.initial
ps.initial.CompositionVsDepth
Section titled “ps.initial.CompositionVsDepth”ps.initial.CompositionVsDepth(*, depth: NDArray[numpy.float64], mole_fraction: dict[str, NDArray[numpy.float64]]) -> None
Overall mole fractions against depth, for one equilibration region.
ps.initial.CompositionVsDepth(depth=[2400.0, 2600.0], mole_fraction={"CO2": [0.01, 0.02], "C1": [0.70, 0.68], "C10": [0.29, 0.30]}).
depth is the depths, strictly rising, in the model’s units, and mole_fraction each
component’s mole fraction at each depth, by the component’s name, one column per component
and one value per depth. Each fraction is from 0 to 1, and the fractions at each depth sum
to 1 within 1e-6. A uniform composition is a one-depth table. It writes ZMFVD (PROPS), the
fractions in its holder’s component order. ps.storage.Package(initial_composition=...)
holds it, at physics/storage/initial_composition; ps.load reads it back.
ps.initial.ConstantTemperature
Section titled “ps.initial.ConstantTemperature”ps.initial.ConstantTemperature(*, temperature: ScalarPropertyInput) -> None
The reservoir’s initial temperature, the same in every cell (RTEMP).
ps.initial.ConstantTemperature(temperature=80.0) starts every cell at 80 degrees.
temperature is a temperature, a bare number in the model’s units (degF in FIELD, degC in
METRIC and LAB). A thermal model (ps.thermal.Package(initial_temperature=), at
physics/thermal/initial_temperature) and a storage package
(ps.storage.Package(temperature=), at physics/storage/temperature) state it, as they
state a TemperatureVsDepth; it writes RTEMP in SOLUTION.
ps.initial.Equilibrium
Section titled “ps.initial.Equilibrium”ps.initial.Equilibrium(*, datum_depth: ScalarPropertyInput, datum_pressure: ScalarPropertyInput, oil_water_contact: Optional[ScalarPropertyInput] = None, gas_water_contact: Optional[ScalarPropertyInput] = None, gas_oil_contact: Optional[ScalarPropertyInput] = None, solution_gor_by_depth: RsVsDepth | None = None, vaporized_oil_by_depth: RvVsDepth | None = None, bubble_point_by_depth: PbVsDepth | None = None, dew_point_by_depth: PdVsDepth | None = None, vaporized_water_by_depth: RvwVsDepth | None = None, temperature_by_depth: TemperatureVsDepth | None = None, composition_by_depth: CompositionVsDepth | None = None, report_datum_depth: Union[ScalarPropertyInput, tuple[ScalarPropertyInput, ...], collections.abc.Mapping[str, tuple[ScalarPropertyInput, ...]], NoneType] = None, threshold_pressures: tuple[ThresholdPressure, ...] = (), vaporization_controls: VaporizationControls | None = None, initial_water_saturation=None, oil_water_capillary_pressure: ScalarPropertyInput = 0, gas_oil_capillary_pressure: ScalarPropertyInput = 0, use_dissolved_gas_table: bool | None = None, use_vaporized_oil_table: bool | None = None, use_vaporized_water_table: bool | None = None, accuracy: Optional[ScalarPropertyInput] = None, pressure_table_points: int | None = None, source: str | None = None) -> None
The initial state in equilibrium: the datum, the contacts and the depth tables.
The simulator starts the reservoir in gravity equilibrium: it takes the pressure at one depth and integrates each phase’s pressure up and down the column, with the contacts splitting the phases.
datum_depthanddatum_pressure: one depth and the pressure there (ft and psia in FIELD, m and barsa in METRIC).oil_water_contactfor a column with an oil leg, orgas_water_contactfor a gas column over water: one of the two (both is refused); a water-only model states neither.gas_oil_contact: the top of the oil leg. Required wherever gas and oil both flow ([initialization.equil.required_value]); a model with no gas cap states it above the reservoir’s top.solution_gor_by_depth(ps.initial.RsVsDepth) orbubble_point_by_depth(ps.initial.PbVsDepth): how much gas a live oil holds at each depth. A live oil needs one, unless the datum is at the gas-oil contact ([physics.initial.depth_table_missing],[physics.initial.datum_off_gas_oil_contact]).initial_water_saturation: a fraction, one value, one per layer or a full array.
Common mistake: a datum pressure typed in the other unit system (psi into a METRIC model).
m.check() then warns at initial/1/datum_pressure
([physics.pressure_gradient.other_unit]).
One Equilibrium states every equilibration region, or initial={region: Equilibrium}
states one per region (numbered from 1), the statements that hold for the whole model
(threshold_pressures, initial_water_saturation, vaporization_controls,
report_datum_depth, pressure_table_points) on region 1’s. Each depth and pressure
is a bare number in the model’s units, or a ps.Quantity.
It writes EQUIL in SOLUTION with the depth tables it states (RSVD, RVVD, PBVD, PDVD, RVWVD,
and RTEMPVD while no thermal or storage package states the temperature), DATUM, DATUMR or
DATUMRX for report_datum_depth, VAPPARS for vaporization_controls, the thresholds’
THPRES (THPRESFT in GRID), SWATINIT in PROPS for initial_water_saturation and EQLDIMS
item 2 for pressure_table_points. An equation-of-state fluid’s composition_by_depth
writes ZMFVD in PROPS, one table per equilibration region. It is ps.Model(initial=...), at
initial/1 (region n’s at initial/<n> in the per-region form), each field below it:
initial/1/datum_pressure.
Examples
Section titled “Examples”An oil column with a gas cap above 2400 m and water below 2600 m, at 250 barsa at 2500 m:
ps.initial.Equilibrium(datum_depth=2500.0, datum_pressure=250.0, oil_water_contact=2600.0, gas_oil_contact=2400.0). The quickstart’s gas field over water:
import petroscript as ps state = ps.initial.Equilibrium(datum_depth=2420.0, datum_pressure=250.0, # m, barsa … gas_water_contact=2450.0) # m state.gas_water_contact # ps.Model(initial=state), at initial/1 2450.0
A live oil under a gas cap, its dissolved gas by depth (FIELD: ft, psia, Mscf/stb):
live = ps.initial.Equilibrium( … datum_depth=8400.0, datum_pressure=4800.0, oil_water_contact=8450.0, … gas_oil_contact=8200.0, … solution_gor_by_depth=ps.initial.RsVsDepth(depth=[8200.0, 8450.0], … solution_gor=[1.27, 1.27]))
ps.initial.ExplicitState
Section titled “ps.initial.ExplicitState”ps.initial.ExplicitState(*, pressure, water_saturation=None, vaporized_water_gas_ratio=None, gas_saturation=None, oil_saturation=None, solution_gor=None, solution_gas_water_ratio=None, vaporized_oil_gas_ratio=None, temperature=None, mole_fraction=None) -> None
The initial state stated cell by cell instead of an equilibrium.
ps.initial.ExplicitState(pressure=[248.0, 250.0, 252.0], water_saturation=0.2) starts each
layer at its own pressure and every cell at a water saturation of 0.2.
The pressure, and the saturations and solution ratios a run states with it, each named as a
run’s cell arrays name it (run.initial["gas_saturation"] states gas_saturation=), and
each a single value, one value per layer (pressure=[4790.0, 4800.0, 4810.0], held in
every cell of its layer) or a full (nx, ny, nz) array. pressure is a pressure (a bare
number in the model’s units, or a ps.Quantity), the saturations fractions of the pore
volume, and the ratios and temperature bare numbers in the model’s units.
mole_fraction is an equation-of-state fluid’s overall mole fraction of each component, by
its name, each cell’s summing to 1 within 1e-6 (a component left unstated is 0).
Each array writes its own card in SOLUTION: PRESSURE, SWAT, SGAS, SOIL, RS, RSW, RV, RVW,
TEMPI and ZMF (component-major, in the component table’s order). It is
ps.Model(initial=...), at initial, each field below it: initial/pressure.
ps.initial.PbVsDepth
Section titled “ps.initial.PbVsDepth”ps.initial.PbVsDepth(*, source: str | None = None, depth: NDArray[numpy.float64], bubble_point_pressure: NDArray[numpy.float64]) -> None
The bubble-point pressure against depth (PBVD), one equilibration region.
ps.initial.PbVsDepth(depth=[2400.0, 2600.0], bubble_point_pressure=[230.0, 240.0]) starts
the oil at a bubble point of 230 at 2400 and 240 at 2600.
depth is each row’s depth (a length) and bubble_point_pressure the oil’s
bubble-point pressure there (a pressure), bare numbers in the model’s units. source notes
where the numbers come from (a loaded deck’s card, a paper); the writer does not read it.
It writes PBVD in SOLUTION (one Equilibrium’s table for each of its equilibration regions).
Flow reads it as it reads RSVD, while the Equilibrium’s use_dissolved_gas_table is
True. It is the bubble_point_by_depth of a ps.initial.Equilibrium, at
initial/1/bubble_point_by_depth.
Rows: (depth, bubble_point_pressure). Each column is a field taking a list, a tuple or a 1-D array, one value per row; PbVsDepth.from_frame(frame) reads them from a frame by name.
ps.initial.PdVsDepth
Section titled “ps.initial.PdVsDepth”ps.initial.PdVsDepth(*, source: str | None = None, depth: NDArray[numpy.float64], dew_point_pressure: NDArray[numpy.float64]) -> None
The dew-point pressure against depth (PDVD), one equilibration region.
ps.initial.PdVsDepth(depth=[2400.0, 2600.0], dew_point_pressure=[230.0, 240.0]) starts the
gas at a dew point of 230 at 2400 and 240 at 2600.
depth is each row’s depth (a length) and dew_point_pressure the gas’s dew-point
pressure there (a pressure), bare numbers in the model’s units. source notes where the
numbers come from (a loaded deck’s card, a paper); the writer does not read it.
It writes PDVD in SOLUTION (one Equilibrium’s table for each of its equilibration regions).
Flow reads it as it reads RVVD, while the Equilibrium’s use_vaporized_oil_table is
True. It is the dew_point_by_depth of a ps.initial.Equilibrium, at
initial/1/dew_point_by_depth.
Rows: (depth, dew_point_pressure). Each column is a field taking a list, a tuple or a 1-D array, one value per row; PdVsDepth.from_frame(frame) reads them from a frame by name.
ps.initial.Restart
Section titled “ps.initial.Restart”ps.initial.Restart(*, case: Annotated[str, Strict(strict=True)], step: Union[Annotated[int, Strict(strict=True)], DayInput], content_hash: Optional[Annotated[str, Strict(strict=True)]] = None, initial_water_saturation=None, skip_history: bool = True, threshold_pressures: Union[tuple[ThresholdPressure, ...], Literal['restart_file']] = ()) -> None
The initial state read from a previous run’s restart file.
ps.initial.Restart(case="history", step="2025-01-01") starts from the state the run named
history wrote on that date. Writes RESTART, and SKIPREST when skip_history.
case names the run that wrote the file: its deck root name, optionally under a
relative directory (both pinned OPM Flow releases resolve it relative to the deck), never
an absolute path or a file name. step is the point on that file: a report-step number
(the deck’s RSNUM), or a day (a date or its text, '2025-01-01'), resolved against this
model’s schedule. The simulator reads the state; PetroScript only states which case and
which point, and no restart file is opened here or anywhere else in the library.
content_hash is provenance recorded at import when the referenced file happens to be
readable; it makes drift detectable and is never load-bearing.
initial_water_saturation is the whole-grid array of manual 8.3.342: a PROPS
declaration that re-scales the capillary pressure curves and is sized by the model’s own
dimensions, so it is stated beside a restart the same way it is stated beside contacts.
Whether the referenced file holds the scaled pressures this needs is the simulator’s to
answer: OPM Flow stops the run when they are missing, naming the vector it wanted.
skip_history says which of the two restart postures this run takes, and it is not
derivable from the restart alone. Stated (SKIPREST, manual 12.3.221) the schedule IS the
history and the simulator walks it up to the restart point, so the schedule has to reach
it. Unstated, the schedule is a CONTINUATION the simulator appends after the restart
point, and its own length says nothing about which points are reachable. Both postures
were measured on both pinned releases from one parent run: with the keyword, a schedule
that stops short fails; without it, the same short schedule runs and the log counts the
restart point plus the schedule’s own steps.
It writes RESTART (the case and the report step), SKIPREST at the head of the schedule
while skip_history holds, SWATINIT for initial_water_saturation and, for
threshold_pressures, EQLOPTS THPRES with THPRES rows ("restart_file": EQLOPTS THPRES
alone). It is
ps.Model(initial=...), at initial, each field below it: initial/case.
ps.initial.RsVsDepth
Section titled “ps.initial.RsVsDepth”ps.initial.RsVsDepth(*, source: str | None = None, depth: NDArray[numpy.float64], solution_gor: NDArray[numpy.float64]) -> None
The initial solution gas-oil ratio against depth (RSVD), one equilibration region.
ps.initial.RsVsDepth(depth=[2400.0, 2600.0], solution_gor=[120.0, 100.0]) starts the oil
with 120 of dissolved gas at 2400 and 100 at 2600.
depth is each row’s depth (a length) and solution_gor the oil’s dissolved gas-oil
ratio there (surface gas per surface oil), bare numbers in the model’s units. source
notes where the numbers come from (a loaded deck’s card, a paper); the writer does not read
it.
It writes RSVD in SOLUTION (one Equilibrium’s table for each of its equilibration regions),
and Flow reads it while the Equilibrium’s use_dissolved_gas_table is True, which stating
the table makes it unless the flag is stated. It is the solution_gor_by_depth of a
ps.initial.Equilibrium, at initial/1/solution_gor_by_depth.
Rows: (depth, solution_gor). Each column is a field taking a list, a tuple or a 1-D array, one value per row; RsVsDepth.from_frame(frame) reads them from a frame by name.
ps.initial.RvVsDepth
Section titled “ps.initial.RvVsDepth”ps.initial.RvVsDepth(*, source: str | None = None, depth: NDArray[numpy.float64], vaporized_oil_gas_ratio: NDArray[numpy.float64]) -> None
The initial vaporized oil-gas ratio against depth (RVVD), one equilibration region.
ps.initial.RvVsDepth(depth=[2400.0, 2600.0], vaporized_oil_gas_ratio=[1.0e-4, 0.5e-4])
starts the gas carrying 1e-4 of oil at 2400 and 0.5e-4 at 2600.
depth is each row’s depth (a length) and vaporized_oil_gas_ratio the gas’s vaporized
oil-gas ratio there (surface oil per surface gas), bare numbers in the model’s units.
source notes where the numbers come from (a loaded deck’s card, a paper); the writer does
not read it.
It writes RVVD in SOLUTION (one Equilibrium’s table for each of its equilibration regions),
and Flow reads it while the Equilibrium’s use_vaporized_oil_table is True, which stating
the table makes it unless the flag is stated. It is the vaporized_oil_by_depth of a
ps.initial.Equilibrium, at initial/1/vaporized_oil_by_depth.
Rows: (depth, vaporized_oil_gas_ratio). Each column is a field taking a list, a tuple or a 1-D array, one value per row; RvVsDepth.from_frame(frame) reads them from a frame by name.
ps.initial.RvwVsDepth
Section titled “ps.initial.RvwVsDepth”ps.initial.RvwVsDepth(*, source: str | None = None, depth: NDArray[numpy.float64], vaporized_water_gas_ratio: NDArray[numpy.float64]) -> None
The initial vaporized water-gas ratio against depth (RVWVD), one equilibration region.
ps.initial.RvwVsDepth(depth=[2400.0, 2600.0], vaporized_water_gas_ratio=[2.0e-5, 2.0e-5])
starts the gas carrying 2e-5 of water at every depth.
depth is each row’s depth (a length) and vaporized_water_gas_ratio the gas’s
vaporized water-gas ratio there (surface water per surface gas), bare numbers in the model’s
units. source notes where the numbers come from (a loaded deck’s card, a paper); the
writer does not read it.
It writes RVWVD in SOLUTION (one Equilibrium’s table for each of its equilibration regions),
and Flow reads it while the Equilibrium’s use_vaporized_water_table is True, which
stating the table makes it unless the flag is stated. It is the vaporized_water_by_depth
of a ps.initial.Equilibrium, at initial/1/vaporized_water_by_depth.
Rows: (depth, vaporized_water_gas_ratio). Each column is a field taking a list, a tuple or a 1-D array, one value per row; RvwVsDepth.from_frame(frame) reads them from a frame by name.
ps.initial.TemperatureVsDepth
Section titled “ps.initial.TemperatureVsDepth”ps.initial.TemperatureVsDepth(*, depth: NDArray[numpy.float64], temperature: NDArray[numpy.float64]) -> None
The initial reservoir temperature against depth (RTEMPVD), one equilibration region.
ps.initial.TemperatureVsDepth(depth=[2000.0, 3000.0], temperature=[80.0, 110.0]) starts the
region at 80 degrees at a depth of 2000 and 110 at 3000, interpolated between.
depth (a length, not falling from row to row) and temperature (a temperature) are
bare numbers in the model’s units. It writes RTEMPVD in SOLUTION, one table for each
equilibration region; ps.load reads TEMPVD, its other name, as RTEMPVD. A thermal model
(ps.thermal.Package(initial_temperature=), at physics/thermal/initial_temperature) or
a storage package (ps.storage.Package(temperature=), at physics/storage/temperature)
states it; a run with neither states it on its equilibrium,
ps.initial.Equilibrium(temperature_by_depth=), at initial/1/temperature_by_depth,
which is written only while no package states a temperature.
Rows: (depth, temperature). Each column is a field taking a list, a tuple or a 1-D array, one value per row; TemperatureVsDepth.from_frame(frame) reads them from a frame by name.
ps.initial.ThresholdPressure
Section titled “ps.initial.ThresholdPressure”ps.initial.ThresholdPressure(*, from_region: Optional[Annotated[int, Strict(strict=True)]] = None, to_region: Optional[Annotated[int, Strict(strict=True)]] = None, fault: str | None = None, pressure: Optional[ScalarPropertyInput] = None) -> None
Threshold pressure between two equilibration regions, or across a fault.
ps.initial.ThresholdPressure(from_region=1, to_region=2, pressure=5.0): no flow crosses
between equilibration regions 1 and 2 until the potential difference passes 5.
A stated pressure (a pressure: a bare number in the model’s units, or a ps.Quantity)
is the potential difference that must be exceeded
before flow crosses: between the regions from_region and to_region
(THPRES), or across the fault fault names (THPRESFT, one of the model’s
ps.Fault names). A threshold states one of the two. On a region pair,
leaving it unstated asks the simulator to derive the threshold from the
initial conditions instead, which is a different declaration from a stated
zero: a computed threshold initially isolates the pair, while zero leaves
it open. A fault’s threshold is always stated, and not negative: Flow derives none across
a fault. Both forms sit in one list, the threshold_pressures of
ps.initial.Equilibrium (region 1’s in the per-region form) or of ps.initial.Restart.
A region pair writes a THPRES row in SOLUTION and switches the thresholds on (EQLOPTS
THPRES in RUNSPEC); a fault writes a THPRESFT row in GRID. The n-th of the list is at
initial/1/threshold_pressures/<n> (a restart’s at initial/threshold_pressures/<n>).
PetroScript is licensed under the Apache License 2.0. © 2026 Blauweiss EDV LLC. PetroScript by Blauweiss AI.For AI agents: llms.txt