ps.fluid
ps.fluid.BlackOil
Section titled “ps.fluid.BlackOil”ps.fluid.BlackOil(*, oil: LiveOil | DeadOil | ConstantCompressibilityOil | CO2LiveOilPVT | None = None, gas: DryGas | WetGas | VaporizedWaterGasPVT | None = None, water: Water | None = None, oil_surface_density: Optional[ScalarPropertyInput] = None, gas_surface_density: Optional[ScalarPropertyInput] = None, water_surface_density: Optional[ScalarPropertyInput] = None, diffusion: Diffusion | None = None, temperature: Optional[ScalarPropertyInput] = None) -> None
A black-oil fluid system: its phases’ PVT tables and surface densities in one PVT region.
Use it for three phases (oil, gas, water), for oil and gas, or for one phase alone. Two-phase
oil-water is ps.fluid.OilWater and gas-water ps.fluid.GasWater: a model whose
BlackOil flows one of those pairs is refused, naming the class to use.
oil:ps.pvt.LiveOil(gas dissolved in the oil),ps.pvt.DeadOilorps.pvt.ConstantCompressibilityOil.gas:ps.pvt.DryGas, orps.pvt.WetGas(oil vaporized in the gas).water:ps.pvt.Water.oil_surface_density,gas_surface_density,water_surface_density: each phase’s density at surface conditions, kg/m3 in METRIC, lb/ft3 in FIELD, g/cc in LAB. An oil or gas density left out is refused ([fluids.density.oil.missing],[fluids.density.gas.missing]); a water density left out is a warning (fluids.density.water.defaulted), and Flow takes fresh water’s.temperature: the temperature the tables are stated at (degC, degF); it writes no card, and the gas z-factor check reads it.diffusion: the region’s molecular diffusion (ps.pvt.Diffusion); None states none.
Common mistakes: a live oil needs a gas table beside it, and its initial state a depth table
(ps.initial.Equilibrium(solution_gor_by_depth=ps.initial.RsVsDepth(...))) unless the
datum is at the gas-oil contact (the datum pressure is then the bubble point); otherwise the
model is refused ([physics.initial.datum_off_gas_oil_contact],
[physics.initial.depth_table_missing]). A ps.pvt.LiveOil’s last family needs its
undersaturated rows ([physics.pvt.undersaturated_missing]).
The densities write DENSITY, one record per PVT region (a loaded deck’s GRAVITY loads as the
densities it means and is written back as GRAVITY while they are still its own), and each
table writes its own card. The run’s phases are the system’s: OIL, GAS and WATER for the
tables it states, DISGAS beside a live oil, VAPOIL beside a wet gas and VAPWAT beside a gas
with vaporized water. It is ps.Model(fluid=...), at fluid/1; fluid={region: system} states one per PVT region, numbered from 1, at fluid/<n>.
Two cases read oddly under this name:
- Water only:
BlackOil(water=...), and the deck switches on WATER alone. - CO2 or H2 storage: the storage package in
Model.physicssupplies the PVT, so the system states no table for the phases the package covers. The phase set is the deck’s own and is kept exactly: OIL GAS with the brine as the oil, or GAS WATER.
Examples
Section titled “Examples”Three phases in METRIC (barsa, sm3/sm3, rm3/sm3, cP, kg/m3):
import petroscript as ps fluid = ps.fluid.BlackOil( … oil=ps.pvt.LiveOil(solution_gor=[50.0, 100.0, 100.0], # sm3/sm3 … pressure=[100.0, 200.0, 300.0], # barsa; the last row … oil_fvf=[1.20, 1.30, 1.28], # is undersaturated … oil_viscosity=[1.0, 0.8, 0.85]), … gas=ps.pvt.DryGas(pressure=[50.0, 400.0], gas_fvf=[0.02, 0.003], … gas_viscosity=[0.013, 0.025]), … water=ps.pvt.Water(reference_pressure=200.0, fvf=1.01, compressibility=4.5e-5, … viscosity=0.4, viscosibility=0.0), … oil_surface_density=850.0, gas_surface_density=0.9, water_surface_density=1020.0, … ) type(fluid.oil).name ‘LiveOil’
ps.fluid.Compositional
Section titled “ps.fluid.Compositional”ps.fluid.Compositional(*, equation_of_state: Literal['peng_robinson', 'soave_redlich_kwong'], components: Components, binary_interaction_coefficients: dict[tuple[str, str], float] = {}, temperature: Optional[ScalarPropertyInput] = None, surface_temperature: Optional[ScalarPropertyInput] = None, surface_pressure: Optional[ScalarPropertyInput] = None, compositions: tuple[Composition, ...] = (), water: Water | None = None, water_surface_density: Optional[ScalarPropertyInput] = None) -> None
An equation-of-state fluid: its components, the equation of state and the pairs’ k_ij.
ps.fluid.Compositional(equation_of_state="peng_robinson", components=ps.pvt.Components(...), binary_interaction_coefficients={("CO2", "METHANE"): 0.1}, surface_temperature=15.0, surface_pressure=1.0) is an oil and gas described by its components instead of tables.
equation_of_state is "peng_robinson" or "soave_redlich_kwong", stated: it changes
every answer. components is the component table (ps.pvt.Components).
binary_interaction_coefficients is each pair’s k_ij by the components’ names: a pair is
unordered (k_ij = k_ji), held once in component order, and a pair left unstated is 0. A
name the table does not hold, a component paired with itself and one pair stated twice with
different values are refused. temperature is the reservoir temperature (kind temperature),
stated here unless the initial state states one. surface_temperature and
surface_pressure are the conditions the produced stream is flashed at to give surface
volumes (kinds temperature and pressure); None leaves each to the engine. compositions are
the injection gases the fluid declares once, each a ps.pvt.Composition of its components
under a name of its own, which an injector names (ps.wells.InjectedStream(composition=)).
water is the water phase’s PVT (ps.pvt.Water), immiscible with
the components, and water_surface_density its density at surface conditions. There is no
oil or gas surface density: the equation of state computes them.
The run’s phases are OIL and GAS, WATER where water is stated, and COMPS counts the
components. It writes EOS, BIC (every pair, the lower triangle row by row), RTEMP from
temperature and STCOND from the surface conditions; the table writes its own cards. OPM
Flow does not run an equation-of-state fluid. It is ps.Model(fluid=...), at fluid/1.
ps.fluid.GasWater
Section titled “ps.fluid.GasWater”ps.fluid.GasWater(*, gas: DryGas | WetGas | VaporizedWaterGasPVT | None = None, water: Water | None = None, oil_surface_density: Optional[ScalarPropertyInput] = None, gas_surface_density: Optional[ScalarPropertyInput] = None, water_surface_density: Optional[ScalarPropertyInput] = None, diffusion: Diffusion | None = None, temperature: Optional[ScalarPropertyInput] = None) -> None
A gas-water fluid system: gas and water PVT and surface densities in one PVT region.
ps.fluid.GasWater(gas=dry_gas, water=water, gas_surface_density=0.8, water_surface_density=1020.0) is a gas reservoir with water.
Every other phase set is a ps.fluid.BlackOil: three phases, oil and gas, or one
phase alone.
gas and water are the phases’ PVT tables (ps.pvt). oil_surface_density,
water_surface_density and gas_surface_density are each phase’s density at surface
conditions (a density: kg/m3 in METRIC, lb/ft3 in FIELD, g/cc in LAB); the oil density a
gas-water deck states is kept and written back, and Flow never reads it. diffusion is the
region’s molecular diffusion (ps.pvt.Diffusion; None states none). temperature is
the temperature the tables are stated at (kind temperature: a bare number in the model’s
units, or a ps.Quantity). An isothermal run writes no card for it; the implied z-factor
check reads it (z = Bg p T_sc / (p_sc T)).
The run’s phases are GAS and WATER (VAPWAT too beside a gas with vaporized water); a deck’s
GASWAT, which Flow reads as those two cards, loads as this system. The
densities write DENSITY, one record per PVT region (a loaded deck’s GRAVITY loads as the
densities it means and is written back as GRAVITY while they are still its own), and each
table writes its own card. It is ps.Model(fluid=...), at fluid/1; fluid={region: system} states one per PVT region, numbered from 1, at fluid/<n>.
Examples
Section titled “Examples”import petroscript as ps fluid = ps.fluid.GasWater( # metric units … gas=ps.pvt.DryGas(pressure=[50.0, 150.0, 250.0, 350.0], # barsa … gas_fvf=[0.0244, 0.0082, 0.0052, 0.0039], # rm3/sm3 … gas_viscosity=[0.0135, 0.0155, 0.0185, 0.0215]), # cP … water=ps.pvt.Water(reference_pressure=250.0, fvf=1.02, compressibility=4.4e-5, … viscosity=0.3, viscosibility=0.0), … gas_surface_density=0.78, water_surface_density=1000.0, # kg/m3 … temperature=90.0) # degC m = ps.load(“tests/results_fixtures/QUICKSTART/MERLE.DATA”) m.set(“fluid”, fluid).get(“fluid/1/gas_surface_density”) 0.78
ps.fluid.OilWater
Section titled “ps.fluid.OilWater”ps.fluid.OilWater(*, oil: LiveOil | DeadOil | ConstantCompressibilityOil | CO2LiveOilPVT | None = None, water: Water | None = None, oil_surface_density: Optional[ScalarPropertyInput] = None, gas_surface_density: Optional[ScalarPropertyInput] = None, water_surface_density: Optional[ScalarPropertyInput] = None, diffusion: Diffusion | None = None, temperature: Optional[ScalarPropertyInput] = None) -> None
An oil-water fluid system: oil and water PVT and surface densities in one PVT region.
ps.fluid.OilWater(oil=dead_oil, water=water, oil_surface_density=850.0, water_surface_density=1020.0) is a dead oil with water.
Every other phase set is a ps.fluid.BlackOil: three phases, oil and gas, or one
phase alone.
oil and water are the phases’ PVT tables (ps.pvt). oil_surface_density,
water_surface_density and gas_surface_density are each phase’s density at surface
conditions (a density: kg/m3 in METRIC, lb/ft3 in FIELD, g/cc in LAB); the gas density an
oil-water deck states is kept and written back, and Flow never reads it. diffusion is the
region’s molecular diffusion (ps.pvt.Diffusion; None states none). temperature is
the temperature the tables are stated at (kind temperature: a bare number in the model’s
units, or a ps.Quantity). An isothermal run writes no card for it; the implied z-factor
check reads it (z = Bg p T_sc / (p_sc T)).
The run’s phases are OIL and WATER. The densities write DENSITY, one record per PVT region
(a loaded deck’s GRAVITY loads as the densities it means and is written back as GRAVITY
while they are still its own), and each table writes its own card. It is
ps.Model(fluid=...), at fluid/1; fluid={region: system} states one per PVT
region, numbered from 1, at fluid/<n>.
PetroScript is licensed under the Apache License 2.0. © 2026 Blauweiss EDV LLC. PetroScript by Blauweiss AI.For AI agents: llms.txt