Skip to content

Chapter 4 — Reading a finished run

A run leaves its files in a folder. ps.results.open(folder) reads them by PetroScript’s names, the names a model asks for them by. Here case_dir is a finished run’s folder, the one deck.run(folder=...) wrote its files into:

run = ps.results.open(case_dir) # one call, then everything off it
oil = run.field("oil_production_rate") # polars: date, value, unit
bhp = run.wells("bottom_hole_pressure") # polars: date, well, value, unit
long_form = run.frame() # date, scope, name, quantity, value, unit
assert set(bhp["well"]) == {"INJ1", "PROD1"}

There is one spelling: a Flow mnemonic is answered with its PetroScript name, so run.field("FOPR") is refused with run.field("oil_production_rate"). run.groups(name) and run.regions(name) read the other scopes the same way. A row is one time step the simulator wrote to the summary, not a report date: Flow writes one at every time step it takes unless the deck thins them (RPTONLY, SUMTHIN), so SPE1CASE1’s first rows sit at days 1, 4 and 11.6, before its first report at day 31. run.times holds those times, in days since the start.

Cell arrays read by name too. run.initial["pressure"] is the state at the start, run.restart(at="2011-06-01")["pressure"] the state at a restart report and run.restarts every one of them by date, run.static["pore_volume"] the arrays that do not change, and run.grid the grid the run wrote. Each array is a read-only (nx, ny, nz) array with NaN in the cells the run did not simulate, so an unmasked average comes back NaN instead of quietly low: weight by run.static["pore_volume"] (the simulator’s own, its net-to-gross included) with np.nansum, which is 0 in those cells.

run.units is the run’s unit system ("metric", "field" or "lab"), read from the restart file’s header, never inferred: a file in another unit system is refused with results.unit_system, and one that marks what a run’s views do not read (a dual-porosity run, a local grid, more than one reservoir) with results.dual_porosity or results.grid_type, so a local grid’s arrays never stand in for the global ones. run.phases is the phases it simulated, oil, water and gas in that order, and run.log what the simulator said while it ran (run.log.warnings, run.log.errors). A reader that needs a file the run did not keep is refused, naming the file: a summary-only folder answers summary reads and refuses the rest.

deck.run() returns the same Run for the folder it wrote, and ps.results.open reads a folder at any time after.

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