Issue codes: the physics checks
PetroScript checks the physics of every model it builds. The checks are plain arithmetic over
what the model states, run by m.check() and at compile time: no simulation, no files. Each
has a code, and one of three tiers:
| Tier | What it means | What you do |
|---|---|---|
| error | The deck cannot run as stated: OPM Flow refuses it or aborts, the arithmetic is ill-posed (a negative cell volume, a porosity above 1, time running backwards), or the model contradicts itself (oil denser than the water under its own contact). | Fix it: ps.compile refuses an error, and no acknowledgement lifts it. |
| warning | Implausible but possible: a datum pressure that reads like another unit, a lift table whose BHP falls below its THP. | Read it. If the model means it, state acknowledged_warnings=["code"] on the model, which turns it into an info row. |
| info | Worth knowing, never blocking: a sector-wedge radial grid, a schedule in which no well opens. | Nothing. |
ps.help(code) explains any code. An acknowledged code that no longer fires is itself an error
(physics.acknowledge.stale): see Acknowledging warnings.
When a check stands down. Field-scale bands (the datum pressure’s unit, rock bands, depth and thickness bands, material balance) stand down for LAB-unit models, restart runs, and core-scale models (a datum shallower than 100 m, 328.08 ft). The laws that hold at any scale never stand down: PVT table order, capillary-pressure order, contact order, a datum pressure above zero, and the porosity and permeability domains. A check that walks the schedule (control feasibility, cumulative volumes) judges every dated change, not only the start.
More on the tiers and the stand-down rules
Every physics guard belongs to one of three tiers:
- E (error) — one of three things, and only these: OPM Flow refuses the deck at load or aborts the run (a rising
PVDG Bg, a control mode on an inactive phase); the arithmetic is
ill-posed (negative-volume cells, porosity above 1, time running
backwards); or the model contradicts itself in a way no real deck does
(oil denser than the water under its own stated contact, a table out of
the order its law requires).
Errors block compiling (
ps.compilerefuses them) and can never be acknowledged away. Each error code names its basis — the Flow witness, or its place on the ill-posed or contradiction list — inERROR_BASIS(petroscript.validation.catalog), and a law holds the source to that table. - W (warning) — implausible but conceivable: oil denser at the datum than
its own column allows, a well’s lift table whose bottom-hole pressure falls below its
tubing-head pressure, a datum pressure that reads as another unit. The model is built, but the
warning demands an explicit
acknowledged_warnings=["code"], which demotes it to an informational issue. Acknowledgment is a statement of intent, not a bypass: it never touches errors. - I (info) — worth stating, never blocking: a sector-wedge radial grid, a schedule in which no well ever opens. Informational issues require no action.
Acknowledgments must stay true. An acknowledged code whose warning does not
fire on the current model is itself an error (physics.acknowledge.stale):
the model would be claiming a weirdness it does not have. See
Acknowledging warnings below.
Guards are plain arithmetic over the declared model, evaluated at
model.check() and compile time — no simulation, no file I/O, cost proportional to the
model itself. A guard stands down silently only when its input is genuinely
not computable from the declared objects (an explicit tensor it cannot
reduce, an unsupported unit system, an unparseable date); malformed input is
an error owned by construction-time validation, never a silent pass. Where a
guard walks the schedule — control feasibility, cumulative volumes, shut
tracking — it applies at every event, not just the initial state: a BHP
limit that is infeasible as a day-30 retarget is judged exactly like an
infeasible initial control.
Field-scale plausibility bands (the datum pressure’s unit, rock bands, depth and thickness bands, material balance) stand down under three triggers: LAB-unit models, restart runs (the restart file holds the initial state), and core/laboratory-scale equilibrations (datum depth shallower than 100 m, which is 328.08 ft in FIELD): pseudo-fluids and bench-top datums are legitimate models that field physics must not judge. The laws that hold at any scale never stand down under any trigger: PVT table monotonicity and the PVTO family crossing, capillary-pressure order, contact order, a non-positive datum pressure, and the porosity and permeability domains. Reference checks — dangling region ids, dead-cell aquifer connections, interior-face boundary conditions — are scale-free too. Contact order is judged, as Flow judges it, only with oil, water and gas all active.
Pressure and initialization
Section titled “Pressure and initialization”| Code | Tier | What it checks |
|---|---|---|
physics.pressure_gradient.nonpositive_datum | error | Datum pressure at or below zero. |
physics.pressure_gradient.other_unit | warning | The datum pressure over the model’s own water column at the datum depth (atmospheric pressure plus the water’s gradient at the datum times the depth: the fact initial/<eq>/datum_pressure_over_water_column), when the pressure read in another unit lands nearer that column than the pressure as stated (bar under FIELD; psi or kPa under METRIC), or when the datum depth read in the other system’s length (m under FIELD, ft under METRIC) does so and that reading, not the depth as stated, lies inside the region’s cells (Cartesian and radial grids). |
physics.equilibration.unsealed_contrast | warning | Adjacent equilibration regions whose initial pressures, each projected from its own datum through its own phase columns (gas, oil and water legs between its contacts, densities rho_w,s/Bw, (rho_o,s + Rs rho_g,s)/Bo and (rho_g,s + Rv rho_o,s)/Bg read as Flow reads them), differ by more than 145 psi (FIELD) / 10 bar (METRIC) at their shared-face depth, with no barrier between them — no THPRES pair, no declared fault on the shared faces, no zero (or effectively zero) face multiplier. |
physics.initial.depth_table_missing | error | EQUIL item 7 (live oil), 8 (wet gas) or 12 (humid gas) above 0 with no RSVD or PBVD, RVVD or PDVD, RVWVD table. |
physics.initial.datum_off_gas_oil_contact | error | A live oil (item 7) or wet gas (item 8) whose item is 0 or not stated, with the datum depth not equal to the gas-oil contact, compared exactly as Flow compares them. Empty equilibration regions are skipped, as Flow skips them. |
physics.initial.depth_table_ignored | warning | An RSVD, PBVD, RVVD, PDVD or RVWVD table stated while its EQUIL item is 0 or not stated. |
physics.initial.vaporized_water_zero | warning | A humid gas (VAPWAT) with item 12 at 0 and the datum off its contact. |
physics.initial.datum_zone_phase_inactive | error | A datum below the water contact in a model without water, or above the gas-oil contact (gas-water contact without oil) in a model without gas; an unstated gas-oil contact is Flow’s 0. |
physics.initial.array_missing | error | An explicit initial state without SWAT (water active, two or more phases), SGAS (gas and oil), RS (dissolved gas) or RV (vaporized oil). |
physics.initial.equilibration_spans_pvt_regions | warning or info | An equilibration region holding active cells of more than one PVT region; the message states the pressure error at the water contact and the contact shift it implies, dh |rho_p - rho_q| / (rho_w - rho_o). A warning where the shift exceeds the thickness of the layer holding the contact, else information; information without geometry (corner-point grids). |
physics.saturation.closure | error | Direct-initialization phase saturations must sum to 1 per cell within 1e-3 (or to at most 1 when one active phase is omitted as the remainder). |
physics.saturation.outside_relperm_span | warning | Direct-initialization water saturation outside the tabulated relperm saturation span (tolerance 1e-6). |
physics.swatinit.no_capillary_pressure | warning | An equilibrated initial water saturation (SWATINIT), single or regional, stated where a water-oil table some saturation region uses (SWOF or SWFN) has an identically zero capillary pressure column. |
Why each check exists:
physics.pressure_gradient.nonpositive_datum
Arithmetic, not judgment: a hydrostatic column has to hang from a real pressure, and no unit system makes zero or a negative one meaningful.
physics.pressure_gradient.other_unit
A unit-slip catcher, with no band of its own: over- and under-pressure are a reservoir’s, and the ratio is a fact, never a finding. A pressure typed in the other unit is off by 14.5 (100 for kPa), further than any reservoir stands from its water column; the test is which reading is nearer in ratio. The corpus and the examples run from 0.75 to 2.7 and stay silent; three corpus decks at 7.2 (699 bar at 1000 m) and the examples that carry one system’s numbers under the other’s keyword are named. A depth is named only with the grid’s agreement, because a reservoir 1.8 times its water column already reads nearer in metres on the pressure alone (the seeds, at 2.2, among them). It stands down with the field bands.
physics.equilibration.unsealed_contrast
The OPM Flow manual’s THPRES section warns that communicating cells in different EQLNUM regions produce “an unstable initial equilibration”: the first timesteps then model the missing seal, not the field. Genuine seals hold pressures of order 1–10 bar (the manual’s own THPRES example spans 0.6–7 bar), so a contrast an order of magnitude beyond that with nothing holding it is compartmentalized initialization without compartment walls. Deliberate unsealed contrasts acknowledge.
physics.initial.depth_table_missing
Flow refuses to initialise (“RSVD or PBVD table not available”, and the RVVD and RVWVD twins; rc 1 on 2026.04).
physics.initial.datum_off_gas_oil_contact
With no table Flow saturates the oil (gas) at the contact’s pressure, which it takes from the datum, and refuses a datum elsewhere (“datum depth must be at the gas-oil-contact”, rc 1). A model that states no item 7 and no table meets this whenever its datum is off the contact.
physics.initial.depth_table_ignored
Flow reads no table and saturates at the contact without a word: SPE1 with RSVD Rs 0.5 and item 7 at 0 starts at Rs 1.53 in every cell. Eight corpus decks carry such dead tables.
physics.initial.vaporized_water_zero
Flow sets the gas’s water vapour to 0 in every cell (“Rvw is set to 0.0 in all cells”).
physics.initial.datum_zone_phase_inactive
Flow cannot tell which phase the datum pressure belongs to and refuses (“Don’t know how to interpret EQUIL datum depth in GAS zone in model without active gas phase”, rc 1).
physics.initial.array_missing
Flow requires each and refuses to initialise (“requires the RS keyword …”, rc 1 for each on 2026.04).
physics.initial.equilibration_spans_pvt_regions
Flow builds each equilibration region’s pressure with its first active cell’s PVT tables: SPE1 with layer 1 in a second PVT region under one EQLNUM starts layer 2 1.4 psi off its own hydrostatic pressure and moves about 1 psi in one day with every well shut (2026.04).
physics.saturation.closure
Saturations are volume fractions of the same pore space; a sum away from unity creates or destroys fluid mass at time zero and the material balance is wrong before the first step.
physics.saturation.outside_relperm_span
Cells start at saturations where no tabulated mobility exists, so the simulator extrapolates or clamps the endpoints — the initial flow field is then an artifact of table layout, not of the rock.
physics.swatinit.no_capillary_pressure
SWATINIT is honoured by scaling the Pcow curve until the stated saturation is the equilibrium one, so a flat column leaves nothing to scale. Measured on both pinned releases: with the column flat, initial water in place came back identical to the same deck carrying no SWATINIT at all; with it live, the stated saturation was honoured exactly. Neither release warns — the keyword is logged as read and then has no effect, which is precisely why the model says so. Decks kept deliberately parallel to a Pc-bearing sibling acknowledge.
Material balance
Section titled “Material balance”| Code | Tier | What it checks |
|---|---|---|
physics.volumetrics.exceeds_stoiip | warning | Cumulative scheduled oil production, observed history apart from target-rate upper bounds, against the stock-tank oil initially in place: each region’s pore volume between its contacts, read from the grid after its program (PORO, NTG, ACTNUM and the region maps as Flow reads them), grown by the ROCK pore-volume factor 1 + X + X^2/2 at the datum pressure, less connate water, over the initial oil’s Bo at the datum as Flow reads it (Rs from RSVD, PBVD or the gas-oil contact; 1/Bo interpolated at that Rs and pressure). |
physics.volumetrics.exceeds_giip | warning | Cumulative scheduled gas production, history apart from targets, against an upper-bound gas initially in place plus every gas the schedule injects: the pore volume above the water contact (read after the grid program), grown by the ROCK factor, over Bg at the datum (1/Bg linear in pressure along PVDG or PVTG’s saturated line). |
physics.volumetrics.implausible_recovery | info | The schedule’s oil recovery, history alone (in_place/field/history_recovery) or history then rate targets (forecast_recovery), past the largest maximum displacement efficiency the model’s own end points reach, 1 - Sor Boi / ((1 - Swc) Bo,max) for each saturation region (displacement/<sat>/max_displacement_efficiency), under end-point scaling with each cell’s scaled residual oil and connate water. Solvent, miscible and thermal models are not held to it; on a model whose gas carries vaporized oil the oil in place is not computed. It cites both facts. |
physics.voidage.overpressuring | info | In a closed tank (no aquifer, boundary or source term), scheduled water injection exceeding production at reservoir conditions, W_i Bw against N_p Bo + (G_p - N_p Rs) Bg + W_p Bw, by enough that the datum pressure plus the tank’s rise passes the lowest bottom-hole pressure limit an injector states. The net volume over each equilibration region’s total compressibility times its pore volume is the tank’s pressure rise (in_place/field/closed_tank_pressure_rise; injected_pore_volumes beside it), with the volume factors read at the datum as Flow reads them; injected gas is not counted (the free gas it sends to the producers is not in the schedule). Not computed when a rate cannot be summed; the schedule walk fails safe: an event on a well it does not read marks the rates unknown. |
physics.voidage.group_without_producers | warning | Group injection under voidage-replacement control on a group whose subtree holds no producer anywhere in the schedule — producers introduced mid-schedule and groups moved by a later tree statement count — with no voidage source group named. |
Why each check exists:
physics.volumetrics.exceeds_stoiip
A tank cannot deliver more oil than it holds, but this tank is an approximation of what Flow counts, so it cannot prove a contradiction: history and a rate target past it are both warnings, and the message names the tank, the history and the target part. The tank omits what Flow may count: end-point scaling (an ENDSCALE SWL below the table’s connate water), pore-volume edits (MULTPV in GRID or EDIT, PORV, MULTREGP), ROCK records by region or ROCKTAB, oil vaporized in the gas (VAPOIL), transition zones, and gas dissolved in water; it reads history at full rate, so an efficiency factor below 1 overstates it. On SPE1 the computed tank lands within 0.1% of Flow’s own STOIIP. A refusal would need an exact in-place volume, which these checks do not compute.
physics.volumetrics.exceeds_giip
Same conservation argument for the gas cap, and the same rule: a warning for history and targets alike, since the tank omits what Flow may count (gas dissolved in water, end-point scaling, pore-volume edits). Injected gas is gas the wells may withdraw: an aquifer gas store starts with none in place.
physics.volumetrics.implausible_recovery
The oil a displacement takes stays within what its own end points displace. The tank omits what Flow may count, so this is an estimate held against an estimate and informs: a fixed recovery bound would be one typical field’s (some water drives recover 35-75%), and a warning on history would need every corpus history fire to be a real defect.
physics.voidage.overpressuring
Water and rock are nearly incompressible, so net injection into a sealed volume drives pressure up by the rise the fact states; the rise alone is the fact’s, never a row. Past an injector’s own limit the injection is BHP-limited and the scheduled volume is not injected, and the row names the limit. Measured (2026.04): SPE1CASE1_BRINE’s injector sits on its 9014 psia limit through the run (opm-tests’ reference: WWIR 72,449 falling to 2,339 against 100,000 scheduled); a fixed ratio would be one typical field’s.
physics.voidage.group_without_producers
Voidage replacement is computed from the target group’s own production, so a group of injectors alone has zero voidage and injects nothing at all. Measured on both pinned releases: FWIR is 0.0 at every step and 0.0 in total, while the run reports itself clean and warns about nothing. Both repairs restore the full rate — put the producers in the group, or name their group as the voidage source.
Control feasibility and schedule dynamics
Section titled “Control feasibility and schedule dynamics”Feasibility compares each well’s BHP limit against the reservoir pressure at its shallowest completion, hydrostatically corrected from the equilibration datum with the brine gradient (0.52 psi/ft / 0.1177 bar/m, formation brine at about 1.2 g/cc, the heaviest column a well or a reservoir holds). The judgment replays across every schedule event — control reissues, retargets, well introductions — using the validate-time datum.
| Code | Tier | What it checks |
|---|---|---|
physics.control.producer_cannot_flow | warning | Producer bhp_limit at or above the corrected reservoir pressure at its completions, carried to the reference depth the limit is stated at (the well’s WELSPECS depth when it states one) through a wellbore between empty and full of brine. |
physics.control.injector_cannot_inject | warning | Injector bhp_limit at or below the corrected reservoir pressure at its completions, carried to the depth the limit is stated at in the same way (a wellhead limit counts its brine column). |
physics.control.marginal_drawdown | warning | A producer’s BHP limit within 2% below, or an injector’s within 2% above, the corrected reservoir pressure. |
physics.control.inactive_phase | error or warning | A replayed schedule control, target, limit, or injection stream referencing a phase the model’s formulation does not carry. Tier: E for a control mode, target or injection stream on an inactive phase; W for a limit. |
physics.schedule.time_reversal | error | Every report time is later than the time the schedule has reached from the model’s start, compared to the time of day: a date behind it, the same date again, the start itself, or a date a run of steps has reached. |
physics.schedule.century_step | warning | A single report step longer than 10957.5 days (~30 years). |
physics.schedule.retune_ineffective | warning | A scheduled retune whose maximum timestep is no shorter than every report step it governs, or whose minimum timestep exceeds one of them. |
physics.schedule.retarget_after_history | warning | A retarget (ps.Adjust) of a well at a report time after its last history record, while that record is still its control. |
physics.schedule.reversal_without_hysteresis | info | On a model that states no hysteresis: a well that injects a phase and later produces, or one that injects water and gas in turn. |
physics.schedule.all_wells_shut | info | Every well shut or stopped for the schedule’s entire duration. |
physics.schedule.negative_history_rate | error | Observed history production/injection rates must be non-negative. |
physics.schedule.efficiency_above_unity | error | Well/group efficiency factors above 1. |
physics.schedule.gaslift_without_gas_phase | error | Lift-gas optimization bound to a well in a model with no gas phase. |
Why each check exists:
physics.control.producer_cannot_flow
Inflow requires drawdown, but the judgment is about TIME ZERO only: injection support and repressurization can restore drawdown a t0 snapshot lacks, and the BHP limit need not be the active control. Acknowledge it for a well that comes on after the pressure does.
physics.control.injector_cannot_inject
Injection requires overpressure, judged at TIME ZERO only: production drawdown can open the window later, and the BHP limit need not be the active control. Acknowledge it for a well that comes on after the pressure falls.
physics.control.marginal_drawdown
A sliver of drawdown technically flows but delivers next to nothing and turns the well into a numerical on/off switch around its limit; a real design leaves working pressure margin.
physics.control.inactive_phase
Flow refuses a control mode on an inactive phase at load, and a retarget or an injector of one aborts the run (“Canonical phase 2 is not active”). A limit on an inactive phase is a different thing: Flow says “The constraint will be ignored” and runs, so it warns. The declared control’s twin is well.control.inactive_phase, on the same terms.
physics.schedule.time_reversal
Time is monotone, and a report step has a length. OPM Flow 2026.04 refuses a DATES “not later than the end time of previous report step” at load.
physics.schedule.century_step
One multi-decade step averages away every transient — breakthrough, decline, interference — that the simulation exists to resolve; a deliberate long-horizon coast acknowledges.
physics.schedule.retune_ineffective
The report steps already cut the step shorter than such a maximum, and a minimum above them asks for steps the report schedule will not allow. Either card reads as timestep control and changes nothing — the mirror image of century_step.
physics.schedule.retarget_after_history
A retarget changes one number and keeps the control, so the well stays under its history control, at the last record’s observed rates, to the schedule’s end unless the changed number binds. A forecast needs a control of its own from that date. A retarget at the record’s own report time is part of the history statement and is not named.
physics.schedule.reversal_without_hysteresis
The saturations around the well reverse direction, and with no hysteresis Flow follows the same curves both ways and traps nothing on the way back. One curve is a modelling choice, so the row informs.
physics.schedule.all_wells_shut
Nothing flows, so the run is an expensive equilibrium check. Legitimate for observation runs, but worth stating.
physics.schedule.negative_history_rate
History records report measured volumes; a negative value is a data error, and flow reversals belong on injection events, not negative production.
physics.schedule.efficiency_above_unity
The factor is the on-stream time fraction; more than 100% uptime has no physical meaning and silently scales rates above their targets.
physics.schedule.gaslift_without_gas_phase
The lift gas has no PVT and no surface stream to belong to; the optimizer would allocate a fluid that does not exist.
Schedule policy sanity
Section titled “Schedule policy sanity”| Code | Tier | What it checks |
|---|---|---|
physics.schedule.decorative_econ_limit | warning | Gas-ratio economic limits (maximum_gas_oil_ratio, maximum_water_gas_ratio) in a model with no gas phase. |
physics.schedule.injector_econ_limit | info | Economic production limits attached to injectors. |
physics.schedule.econ_min_above_target | warning | Economic minimum oil rate above the well’s current control target. |
physics.schedule.wtest_reopen_chatter | warning | A well shut by an economic minimum above its target, then periodically re-tested for ECONOMIC recovery. |
physics.schedule.reinjection_above_unity | warning | Group reinjection fraction above 1. |
physics.schedule.vfp_off_axis | warning | A well’s operating rate target outside its VFP table’s flow axis span by more than a factor of 2 in either direction. |
physics.schedule.vfp_thp_off_axis | warning | A tubing-head pressure a well states outside the THP axis of the lift table it holds there: a thp_limit or a thp target against the table the control binds, a ps.Adjust(thp=...) (WELTARG) against the table its well holds at that point (a control’s binding or a dated History’s lift_table moves it), and either inside an action rule’s body, where a binding holds for the rest of that body only; a zero limit (the record’s no-limit) and a value stated by an expression stay silent. |
physics.lift.bhp_below_thp | warning | A production lift table (ps.lift.ProductionTable) a producer binds (a ps.Produce or ps.History lift_table=, or a lift binding, a rule’s included) with a bottom-hole pressure below its tubing-head pressure, no pump or compressor on its lift axis, and not a network’s table. |
physics.lift.injection_bhp_rises_with_rate | info | An injection lift table whose bottom-hole pressure rises with the rate at one tubing-head pressure. |
physics.lift.head_exceeds_water_column | info | A water-injection lift table whose bottom-hole pressure exceeds its tubing-head pressure by more than the model’s own water column to the table’s depth (the heavier of its surface water and its water at a datum). |
physics.schedule.group_target_ungrounded | info | A group oil-rate target more than 100x the summed member-well targets. |
physics.schedule.udq_zero_divisor | warning | A UDQ dividing by a gas quantity in a model with no gas phase, with no ps.Numerics(user_quantity_undefined_value=...) declared. |
physics.schedule.action_condition_unreachable | warning | An action triggering on a pressure beyond the physically reachable range (0–72500 psi FIELD, 0–5000 bar METRIC) on the impossible side. |
physics.schedule.action_condition_tautological | warning | An action comparing pressure against a literal outside the reachable range on the always-true side, with no minimum_wait. |
Why each check exists:
physics.schedule.decorative_econ_limit
The ratio is identically zero forever, so the protection can never trigger; the limit documents an intention the model cannot honor.
physics.schedule.injector_econ_limit
An injector produces nothing for the limit to test; the rows are semantically void and probably meant for the paired producers.
physics.schedule.econ_min_above_target
The well is born dead: it can never meet the minimum it is tested against and shuts at the first economic test. Staged later retargets that make the limit reachable acknowledge.
physics.schedule.wtest_reopen_chatter
Each test reopens the well into the same impossible economics and instantly re-shuts it — a chatter loop that produces nothing and pollutes the well events log.
physics.schedule.reinjection_above_unity
Reinjecting more than the group produces requires a make-up stream that the model does not express; the extra fluid appears from nowhere.
physics.schedule.vfp_off_axis
Every BHP lookup then extrapolates the lift curve from day zero, and extrapolated VFP behavior is notoriously unphysical — the well operates on an invented curve.
physics.schedule.vfp_thp_off_axis
OPM Flow reads the table there by extrapolation and prints no warning. Four corpus decks state one: WVFPDP-01 and -02 (a limit of 75 on [10, 35]) and WVFPEXP-01 and -02 (5 on [10, 35]). A well can also start above the axis with its stated THP inside it (NeqSim W0’s FL1 run: 86.9 bar on day 1 against a top node of 60), which no check of the model sees: span the THP the well starts at.
physics.lift.bhp_below_thp
A producing well’s fluid rises against its own weight and friction, so its bottom-hole pressure stands above its tubing-head pressure unless a pump or compressor adds the energy; a table below it delivers fluid uphill for free. A table no producer binds is no well’s tubing and changes no run: the flowline table five of flowl_c_vfp.ecl, below its head at 10,923 of its 61,560 pressures, is a network branch’s table in the decks that use it (model5’s 5_NETWORK_MODEL5_STDW, gaslift’s GASLIFT-13) and is bound by no well in the fourteen that only state it. The corpus’s tables a well binds fire nowhere; rescoup’s generated well tables do, and their decks are refused at import.
physics.lift.injection_bhp_rises_with_rate
At one tubing-head pressure friction takes more of an injector’s head the faster it injects, so its bottom-hole pressure falls with the rate. No corpus table does it, so it informs until a run backs it.
physics.lift.head_exceeds_water_column
Friction only takes from an injector’s head, so the bottom-hole pressure stands at most the tubing-head pressure plus the water’s weight. No corpus table does it, so it informs until a run backs it.
physics.schedule.group_target_ungrounded
The group control can never bind — the members saturate their own limits far below it — so the group target is decorative and probably a units or magnitude slip.
physics.schedule.udq_zero_divisor
The divisor is identically zero, so the quantity is undefined at every evaluation; downstream controls read whatever the simulator substitutes.
physics.schedule.action_condition_unreachable
The condition can never come true: the action is dead code carried as if it were protection.
physics.schedule.action_condition_tautological
The condition holds at every evaluation, so the action fires every step — usually a periodic policy missing its minimum_wait, executing far more often than intended.
Contacts and saturations
Section titled “Contacts and saturations”| Code | Tier | What it checks |
|---|---|---|
physics.contacts.contact_order | error | Gas-oil contact deeper than the water-oil contact. |
physics.contacts.all_water | warning | Water-oil contact above the grid top while oil-rate producers are scheduled. |
physics.contacts.below_grid | info | Water-oil contact more than 50 total column thicknesses below the grid base, in a column with an oil leg. |
physics.contacts.gas_water_below_grid | warning | The same distance in a gas-water formulation (gas and water active, no oil); in a storage model (CO2STORE or H2STORE), any gas-water contact below the grid base. |
physics.contacts.datum_remote | warning | Equilibration datum more than 1000 m (3281 ft) outside the grid’s depth span. |
physics.contacts.producing_from_water_leg | warning | Every completion of an oil-rate producer below the water-oil contact. |
Why each check exists:
physics.contacts.contact_order
Gravity stacks gas over oil over water; an inverted contact pair describes a fluid column that cannot be in static equilibrium, and equilibration initializes nonsense saturations from it.
physics.contacts.all_water
The reservoir initializes 100% water with no oil anywhere, yet oil production is demanded — the schedule and the initial state describe two different reservoirs. Flow runs it (no oil in place), so it warns; acknowledge it for a deliberate water-only start.
physics.contacts.below_grid
No cell initializes water: every cell sits in the leg above the shallowest contact below the base, oil, or gas when the gas-oil contact is below the base too, and the message names which. Perfectly legal, but it should be a stated choice.
physics.contacts.gas_water_below_grid
Every cell then initializes in the gas leg, so a model written for gas in brine holds no water at all: a saline aquifer stated this way is a tank of gas.
physics.contacts.datum_remote
The entire initial pressure field is then a long-range hydrostatic extrapolation from a point that touches no rock; almost always a mistyped datum depth (genuine off-structure datum conventions acknowledge).
physics.contacts.producing_from_water_leg
The well can only drain the water leg, so it produces water against an oil target from day zero; deliberate water-leg completions (pressure support observation, coning studies) acknowledge.
PVT and fluids
Section titled “PVT and fluids”| Code | Tier | What it checks |
|---|---|---|
physics.pvt.density_order | warning | Surface oil density above surface water density, in every PVT region. |
physics.pvt.reservoir_density_order | error or warning | At each equilibration datum, (rho_oil,surface + Rs x rho_gas,surface) / Bo with Rs and Bo read as Flow reads them (dead oil and oil-water models included), against rho_water,surface / Bw at that pressure, each region with its own PVT tables (one Equilibrium over several equilibration regions is judged in each, as Flow builds each column with its first cell’s PVT region); without a contact, each saturated PVTO node of every PVT region. Tier: E when the oil at an equilibration datum is denser than the water under its stated contact; else W. |
physics.pvt.fvf_subunity | warning | Oil formation volume factor below 0.90 anywhere in the oil tables, when the oil slot holds a liquid. |
physics.pvt.oil_fvf_marginal | warning | Oil FVF in the 0.90–0.98 band. |
physics.pvt.oil_fvf_increases_with_pressure | error | Bo rising with pressure along the dry-oil table or any undersaturated branch. |
physics.pvt.family_bo_crossing | error | Saturated Bo falling as solution GOR rises across live-oil families, compared at a pressure both records state. |
physics.pvt.gas_fvf_non_monotonic | error | Gas FVF rising with pressure inside the table. |
physics.pvt.gas_viscosity_decreasing | error | Gas viscosity falling at any step of the tabulated pressure column. |
physics.pvt.gas_range_below_initial | warning | Dry-gas table ending below the initial datum pressure. |
physics.pvt.rsvd_exceeds_saturated | error or warning | At each equilibration datum, RSVD’s solution GOR (or PBVD’s bubble point read through the saturated line), when EQUIL item 7 asks for a table, against the saturated Rs at the datum pressure. Tier: W past 1.02x, E past 2x. |
physics.pvt.viscosity_range | warning | Phase viscosities outside broad physical bands: oil 0.05–100000 cP, water 0.05–5 cP, gas 0.001–0.2 cP. |
physics.pvt.water_compressibility_absurd | warning | Water compressibility above 1.5e-4 1/bar (~1.03e-5 1/psi). |
physics.pvt.water_fvf_range | warning | Water FVF below 0.90. |
physics.pvt.saturated_nodes | error | A PVTO, PVTG or PVTGW table with fewer than two saturated rows (records). |
physics.pvt.undersaturated_missing | error | A PVTO, PVTG or PVTGW table whose last record states its saturated row alone. |
physics.pvt.column_order | error | A column Flow’s schema orders and the table does not: PVDO’s and PVDG’s FVF and each PVTO record’s Bo not falling strictly (a level step), PVDO’s viscosity falling, a PVTG or PVTGW record’s vaporized ratio not falling strictly. Compared exactly, as Flow compares. |
physics.pvt.bubble_point_order | error | A PVTO record’s bubble point (its first pressure) below the previous record’s while its Rs is higher. |
physics.pvt.rs_rv_product | error | Saturated Rs times saturated Rv at or above 1 at any pressure both lines span (DISGAS with VAPOIL). |
physics.pvt.gas_heavier_than_oil | error or warning | The gas at the datum pressure, (rho_gas,surface + Rv rho_oil,surface) / Bg, at least as dense as the oil there, (rho_oil,surface + Rs rho_gas,surface) / Bo, each equilibration region with its own PVT tables; an oil slot holding a gas is not judged. Tier: E when the region’s gas-oil contact lies inside its active cells with an oil leg under it (the water contact deeper); else W. |
physics.pvt.gas_heavier_than_water | warning | The gas at the datum pressure at least as dense as the water there (when the oil check has not spoken). |
physics.pvt.implied_z_factor | warning | With the fluid’s temperature (or a uniform thermal or storage temperature) stated, every node’s z = Bg p T_sc / (p_sc T) outside a real gas’s 0.2 to 3; without one, every node’s z T beyond any gas where water is liquid (z 0.2 to 3, T 273 to 647 K); and a named unit factor bringing every node inside. |
physics.pvt.total_compressibility_negative | warning or info | On an interval of a saturated line, c_t = [-dBo/dp + dRs/dp (Bg - Bo Rv) / (1 - Rs Rv)] / Bo at or below zero, as the tables state it (and its twin on the gas line). Tier: W where the interval stays at or below zero with the model’s own rock and connate-water compressibility added (c_r + c_t (1 - Swc) + c_w Swc, at each datum reading the tables); else I. |
physics.pvt.phase_order | info | At one pressure on both saturated lines, the gas at least as viscous as the oil, or holding at least as much oil per reservoir volume (Rv / Bg) as the oil phase (1 / Bo). |
physics.pvt.viscosity_trend | info | A viscosity falling with pressure along an undersaturated PVTO record, or along the saturated PVTG line. |
Why each check exists:
physics.pvt.density_order
Stock-tank crude usually floats on water, and an inversion is most often a units or column slip; but oil below 10 degrees API is denser than water and Flow runs it (oil at 1010 kg/m3 against water at 1000 matched its base to five digits), so it warns. The density that decides the initial state is the reservoir one, below.
physics.pvt.reservoir_density_order
An equilibration states oil above water. Oil denser than the water under it contradicts that statement, and Flow follows gravity: a dead oil at Bo 0.85 ran with no oil in place at all. Extra-heavy oil and bitumen are real, so without a stated contact the check reports rather than refuses; an extra-heavy oil is initialized directly, not from contacts. The message names a unit slip only where one alone settles the column: a gas surface density beyond any gas at surface conditions (the gas the oil dissolves carries it), else, past twice the water’s density, which no liquid oil reaches, Rs typed in scf/stb.
physics.pvt.fvf_subunity
Reservoir oil holds dissolved gas and thermal expansion; it should not occupy 10%+ less volume than the same oil at stock tank, and Bo this low is usually a swapped column or a reciprocal. Flow runs it, so it warns; where the shrunken oil ends up denser than the water under its contact, reservoir_density_order refuses the model. Calibrated: the black-oil oil slot does not have to hold a liquid, and the guard stands down when surface oil density is below 100 kg/m3 METRIC / 6.24 lb/ft3 FIELD.
physics.pvt.oil_fvf_marginal
Slightly sub-unity Bo is representable but sits at the edge of real dead-oil behavior; usually the table was built against nonstandard surface conditions and deserves a check.
physics.pvt.oil_fvf_increases_with_pressure
dBo/dp > 0 is negative compressibility — compressed oil expanding. The simulator inverts it into unstable, non-physical pressure response.
physics.pvt.family_bo_crossing
More dissolved gas always swells oil. Crossing families make the saturated envelope non-monotone, and every interpolation between them lands on a fluid that cannot exist. Calibrated: two records that share no pressure node are one undersaturated branch written in two records — the documented idiom for extending past the nodes the first record had room for — so there is nothing to compare and the guard says nothing.
physics.pvt.gas_fvf_non_monotonic
Bg is inversely proportional to pressure through the z-factor; no real-gas correlation produces a rising segment. The simulator would compute negative compressibility for gas.
physics.pvt.gas_viscosity_decreasing
At fixed temperature gas viscosity rises with density, and density with pressure, so the law holds step by step. OPM Flow’s parser declares the PVDG viscosity column increasing and refuses one falling step at load.
physics.pvt.gas_range_below_initial
Every cell’s gas properties are extrapolated beyond the table from day zero, so the whole run rides on extrapolation behavior rather than data; accepted extrapolation acknowledges.
physics.pvt.rsvd_exceeds_saturated
The law holds at each depth, Rs(z) <= Rs_sat(P(z)); it is judged at the datum, where both sides are stated. Flow caps the initial Rs at saturation without a word, so a demand past it is dissolved gas the model states and the run drops. The corpus reaches 1.25x at most, and every unit slip measured is 5.6x or more, so past twice saturation it is refused as a slip. Negative RSVD or RVVD values and PBVD or PDVD pressures at or below zero are refused at construction (initialization.*.range), as is a directly initialized pressure at or below zero.
physics.pvt.viscosity_range
These bands span everything from condensate to cold bitumen and cool brine to hot steam; values outside them are almost always cP/Pa.s slips, which silently rescale every mobility by 1000.
physics.pvt.water_compressibility_absurd
A unit-slip catcher, not a field value: no brine, gas-saturated included, reaches 1.5e-4 1/bar (Osif 1988). The slip it catches is a 1/bar value typed into a FIELD deck, which reads 14.5 times too large (4.67e-5 becomes 6.8e-4 and passed a 1e-3 ceiling). Flow runs even 4.67e-3 1/bar, so it warns. The message states the ceiling and the slip, never a typical brine.
physics.pvt.water_fvf_range
Real Bw lives near [0.95, 1.1]; water cannot lose 10% of its volume downhole. Flow runs Bw 0.85 with every water volume scaled (oil in place moved 30%), so it warns.
physics.pvt.saturated_nodes
Flow refuses it at load (“Saturated PVTO must have at least two rows”): the saturated line cannot be interpolated from one node.
physics.pvt.undersaturated_missing
Flow extends every single-row record from the next record that has undersaturated rows, finds none past the last and refuses the table at load (“The last table must exhibit at least one entry for undersaturated oil!”).
physics.pvt.column_order
Flow refuses each at load (“Non-monotonic values in keyword PVDO … BO need to be entered in strictly decreasing order”; the flat-Bo PVDO witness, W3a). A rising Bo or Bg and a falling PVDG viscosity keep their own codes.
physics.pvt.bubble_point_order
Ill-posed: more dissolved gas needs more pressure to stay in solution, and with the bubble point falling Pb(Rs) has no inverse, so the saturated Rs at a pressure has no single answer. Flow sorts the line by pressure and runs (rc 0). Two records at one bubble point (padded tables start several at the standard pressure) leave the line monotone and are not judged.
physics.pvt.rs_rv_product
Ill-posed: the black-oil split of surface oil and gas into their reservoir phases divides by 1 - Rs Rv. SPE3 with Rv x10 ran (rc 0) through 140 failed well-equation inversions and five time-step chops in one day.
physics.pvt.gas_heavier_than_oil
Under a contact inside the grid the model states a denser gas resting on a lighter oil, a contradiction: Flow builds the gas cap and it sinks at once (SPE1 with its contact in layer 1 and Bg x 0.3, wells shut: layer 1’s Sg fell 0.88 to 0.8716 in one day). Elsewhere it warns: a gas cap or freed gas would sink; with both contacts at one depth (the gas-condensate idiom) no oil lies under the gas and Flow holds the column as stated (the same deck with its water contact at 8340 ft: steps 0 and 1 identical). The message gives the gas’s own weight and the oil it carries, and names Rv where the oil it carries makes it the heavier (a condensate yield typed for Rv, a thousand times it, seen in test decks and a units audit); else Bg’s unit and the surface densities.
physics.pvt.gas_heavier_than_water
A gas zone over that water would sink through it; Flow runs it as stated (SPE1 with Bg x 0.2, rc 0). The message names Rv, as gas_heavier_than_oil’s does, where the oil the gas carries makes it the heavier, in either unit system; Bg’s unit is implied_z_factor’s to name, from the whole table, so this message names no Bg factor (one node’s factor named a Bg 5.6 times too small as the fix).
physics.pvt.implied_z_factor
A unit-slip catcher, not a field value: the band is the gas law’s and liquid water’s. The message names each factor that settles it (FIELD: a dimensionless Bg, rb/scf, ft3/Mscf, pressures in bar, a whole METRIC table; METRIC: rb/Mscf, pressures in psi, a whole FIELD table). At a stated temperature the row names the node, its z, Bg and the temperature, and each slip with the z it gives (Rosa’s rb/scf table typed as rm3/sm3: z 0.182 at 250 barsa and 90 degC, x 5.6146 gives 1.02; z T alone, 60 to 69 K, lies inside the band). The z-factor itself is the fact fluid/<pvt>/implied_z_factor_min and _max, computed at that temperature.
physics.pvt.total_compressibility_negative
A saturated system that shrinks as its pressure falls has no stable state (Singh, Fevang and Whitson). SPE1 started saturated at 4800 psia, its 4014.7-5014.7 psia interval made negative (Bo 2 for 1.827 at Rs 1.618), the injector shut: Flow took 29,312 time steps for its first 12.3 days, down to 6.5e-7 days, through 11 convergence failures and 11 chops, before a 600 s limit stopped it; the control ran ten years in 123. The warning’s fix names the FVF against the ratio over the interval with both bounds (a Bo under, or an Rs over, the value that keeps the line from shrinking). Where the rock’s compressibility outweighs the interval (a near-critical table) it informs. The datum’s value is the fact initial/<eq>/total_compressibility.
physics.pvt.phase_order
Near a critical point the phases converge, so it informs; elsewhere it marks a swapped or mistyped column.
physics.pvt.viscosity_trend
Compressed fluid is denser and no less viscous; Flow reads the column as stated (only the books behind it).
Relative permeability and hysteresis
Section titled “Relative permeability and hysteresis”| Code | Tier | What it checks |
|---|---|---|
physics.relperm.exceeds_unity | warning | Any relative permeability value above 1, interior rows included. |
physics.relperm.nonzero_at_connate | error | A rising relative-permeability column (krw, krg, SOF2’s kro, both SOF3 columns, SLGOF’s krog) above TOLCRIT (1e-6 unless stated) at the table’s first row, as Flow’s binary search for the critical saturation reads it, in every family Flow searches. Here and in the two rows below, a cell left to the simulator (1*) is read as Flow fills it: linearly in the saturation between the stated cells either side, held at the nearest stated cell beyond them. |
physics.relperm.kro_at_max_water | error | A falling relative-permeability column (SWOF’s krow, SGOF’s krog, SLGOF’s krg, SGWFN’s krw) never at or below TOLCRIT, Flow’s way. |
physics.relperm.no_mobile_state | error | A rising relative-permeability column never above TOLCRIT. |
physics.relperm.column_direction | error or warning | A relative-permeability column against its saturation: krw, krg and kro must not fall with their own saturation, krow and krog must not rise as water or gas rises. An error in the families Flow orders at load (SWFN, SGFN, SOF2, SOF3, SLGOF, WSF, GSF), a warning in SWOF, SGOF and SGWFN. |
physics.relperm.gas_table_start | warning | An SGOF whose first gas saturation is not 0. |
physics.relperm.mobile_oil_window | warning | Flow’s mobile-oil windows on the table end points: SOWCR < 1 - SWCR - SGL against water and SOGCR < 1 - SWL - SGCR against gas. It cites the displacement end-point facts. |
physics.relperm.gas_table_short | warning or info | A gas-oil table (SGOF, SLGOF, SGFN) whose last gas saturation is below 1 - Swc. A warning where the saturation region has cells above its gas-oil contact (Cartesian and radial grids), an info row where it has none or PetroScript cannot tell. Its fix keeps krog’s first zero where it is. |
physics.relperm.three_phase_endpoints_disagree | warning | Three-phase models: krow at connate water (SWOF’s first row, SOF3 at So = 1 - Swl - Sgl) against krog at connate gas (SGOF’s first row, SLGOF’s last). |
physics.relperm.step_jump | info | A relative-permeability interval carrying a fifth of the column’s span at ten times both its mean slope and each neighbour’s slope. |
physics.pc.step_jump | info | A capillary-pressure interval of the same shape inside the curve: the first and last intervals are not judged. |
physics.relperm.immobile_window_overlap | error | LET critical saturations of the two phases summing to 1 or more. |
physics.relperm.imbibition_outside_drainage | error | Imbibition connate water/gas endpoints above their drainage baselines. |
physics.relperm.imbibition_trapping_inverted | error | Imbibition critical (trapped) gas above its maximum gas saturation. |
physics.relperm.imbibition_curve_above_drainage | warning | For each pair of saturation and imbibition regions an active cell uses: the imbibition table’s non-wetting relative permeability (gas; oil against water) above the drainage table’s at some saturation. |
physics.pc.surface_tension_range | warning | A J-function surface tension above 75.6 dyn/cm, water’s own against air at its freezing point. |
physics.pc.sign_convention | error | Capillary pressure out of the order or sign its law requires: water-oil Pcow (SWOF, SWFN) rising with water saturation at any step; gas-oil Pcgo (SGOF, SGFN, SLGOF) or gas-water Pcgw falling with gas saturation at any step, or below zero. In a gas-water model OPM reads Pcgw from SWFN and zeroes SGFN’s column, so SGFN there is judged on its order only, which Flow’s parser refuses too. Defaulted (1*) cells are left out, since a fill between stated rows cannot change a step’s sign. |
Why each check exists:
physics.relperm.exceeds_unity
Relative permeability is normally normalized to absolute permeability, but SCAL curves normalized against another base legitimately exceed 1. Both supported OPM Flow releases load, run, and USE such a table without a word, so refusing it would be a gate rather than a guard — the simulator happily computes the resulting super-mobilities.
physics.relperm.nonzero_at_connate
Flow finds each critical saturation as the last row at or below TOLCRIT; with none it reads before the table’s start and refuses the deck (“Value: 18446744073709551615 out of range”, rc 1 on 2026.04 for SPE1 with 0.05 added to SWOF’s krw).
physics.relperm.kro_at_max_water
Flow’s search finds no immobile row and the run aborts (SPE1 with SWOF’s krow ending at 0.05, or SGOF’s krog at 5e-4: rc 139 on 2026.04).
physics.relperm.no_mobile_state
The phase never flows, Flow’s search finds no mobile row and the run aborts (SPE1 with SGOF’s krg 0 throughout: rc 139 on 2026.04).
physics.relperm.column_direction
Flow refuses an ordered column at load (“Non-monotonic values in keyword SWFN”, rc 1); it runs a RANDOM one (rc 0), and its binary search then finds a critical saturation that is not the curve’s.
physics.relperm.gas_table_start
Flow reads the first row as connate gas, the least gas any cell holds: SPE1 with SGOF starting at Sg 0.02 starts every cell, the undersaturated oil leg included, with Sg 0.02 of free gas (rc 0 on 2026.04; Flow’s own warning names only SGL + SWU > 1).
physics.relperm.mobile_oil_window
Oil outside its window never flows; Flow reports the window at initialisation and runs on (OilPhaseConsistencyChecks, non-critical).
physics.relperm.gas_table_short
Flow does not extrapolate the table: it starts each gas-cap cell at the table’s last gas saturation and fills the rest with oil (one test deck’s 0.25 of oil in the gas cap, recovery read 11.6% against 8.5%). A krog whose first zero is at exactly 1 - Swc is a critical oil saturation of 0; Flow computes it as (1 - Sg) - Swc in doubles and aborts when rounding lands below zero (Swc 0.2, 0.1, 0.22 on 2026.04), so the SGOF writer puts that row the fewest units in the last place lower (target.critical_oil_rounding, an info row). The water half is not judged: its fix invites a flat krw tail.
physics.relperm.three_phase_endpoints_disagree
The model states the oil’s relative permeability with connate water and no gas twice, with two values, and the three-phase oil curve reads both; the manuals say they must be the same. 0 of 1,996 corpus pairs differ.
physics.relperm.step_jump
Flow interpolates tables linearly and differentiates them; a step reaches the solver as a near-vertical slope. Information only: no run has measured the harm.
physics.pc.step_jump
As for the relative permeability. Both ends of a capillary-pressure curve steepen by nature: the climb toward connate saturation, and an entry (threshold) pressure, which tables write as a drop to 0 in the last interval (13 corpus decks).
physics.relperm.immobile_window_overlap
The two immobile windows cover the entire saturation axis: no saturation exists at which anything flows, so the model is a sealed rock wearing relperm curves.
physics.relperm.imbibition_outside_drainage
Scanning curves live inside the bounding drainage curve; an imbibition endpoint outside it gives the hysteresis model no valid interpolation space and the scanning logic produces undefined mobilities.
physics.relperm.imbibition_trapping_inverted
Land-type trapping cannot trap more gas than was ever present; the trapping model’s denominator goes non-physical.
physics.relperm.imbibition_curve_above_drainage
Carlson’s and Killough’s scanning curves leave the drainage curve at the reversal and run on or below it; an imbibition curve above the drainage curve has none, and one whose critical saturation is the lower traps nothing. The corpus’s hysteresis decks are silent.
physics.pc.surface_tension_range
A unit-slip catcher: no pair of reservoir fluids has a higher interfacial tension, and Flow reads the value in dyn/cm in every unit system and scales the capillary pressure with it. A laboratory mercury-air value (about 480) or a tension typed in another unit reads this way.
physics.pc.sign_convention
Pcow = Po - Pw falls as water fills the pore space in water-wet, oil-wet and mixed-wet rock alike (Anderson 1987, SPE-15271); its sign is free, because oil-wet rock carries a negative Pcow. Gas is non-wetting to both oil and water, so a gas capillary pressure rises with gas saturation and is never negative. OPM Flow runs a table out of this order without a word and reaches a different answer, so the contradiction is refused.
EOR and package gating
Section titled “EOR and package gating”| Code | Tier | What it checks |
|---|---|---|
physics.polymer.viscosity_reducing | error | Polymer viscosity multiplier below 1 at any concentration. |
physics.polymer.initial_concentration.shape / .range, physics.polymer.initial_molecular_weight.shape / .range | error | Initial polymer state fields must match the grid shape and be non-negative. |
physics.foam.carrier_phase_inactive | error | Foam mobility reduction carried by a phase not active in the model. |
physics.storage.phase_inactive | error | CO2/H2 storage package in a model with no gas phase. |
Why each check exists:
physics.polymer.viscosity_reducing
Dissolved polymer thickens water — that is its entire purpose; drag-reducing agents act on turbulence, not viscosity. A multiplier below 1 makes the flood improve mobility ratio backwards.
`physics.polymer.initial_concentration.shape` / `.range`, `physics.polymer.initial_molecular_weight.shape` / `.range`
A misshapen field silently misassigns concentrations across cells, and negative concentration or molecular weight has no physical meaning.
physics.foam.carrier_phase_inactive
Foam rides its carrier phase; without that phase there is no stream to reduce, and the foam package would act on nothing.
physics.storage.phase_inactive
The stored component exists in the gas phase; without it there is no store — injection would have no phase to put the component into.
Rock and grid geometry
Section titled “Rock and grid geometry”| Code | Tier | What it checks |
|---|---|---|
physics.rock.porosity_bounds | error | Any porosity value outside [0, 1] in an active cell, judged after the grid program (MULTIPLY, COPY and the rest) has run. |
physics.rock.permeability_negative | error | Any negative permeability value in an active cell, judged after the grid program has run. |
physics.rock.porosity_implausible | warning | Peak porosity above 0.45, or the most porous cell below 0.01. |
physics.rock.permeability_implausible | warning | Peak permeability above 5e6 mD, or the most permeable cell below 1e-3 mD. |
physics.contacts.datum_above_surface | warning | A datum depth below zero: above the surface, since depths run positive downward. |
physics.stand_down.bands | info (printed) | The field-scale bands stand down on this model, and why: LAB units, a restart, or a datum shallower than 100 m. |
physics.stand_down.geometry | info (printed) | A grid whose cell geometry PetroScript does not compute yet (corner-point): the in-place, contact and well-against-contact checks stand down. |
physics.rock.compressibility_unstated | warning or info | A model whose wells produce or inject while its rock states no compressibility: a warning when oil or water carries the pressure response, an info row on a gas-water model. Stating compressibility=0.0 records incompressible rock as a choice. |
physics.rock.compressibility_range | warning | Rock compressibility above 5e-3 1/bar (~3.4e-4 1/psi). |
physics.rock.reference_pressure_remote | info | The rock’s pore-volume factor at the datum pressure, 1 + X + X^2/2 with X the compressibility times the datum pressure above the reference pressure (the fact rock/<rk>/pore_volume_factor), more than 2% from 1. Models with a compaction table are not judged. |
physics.rock.kv_above_kh | info | On a model of more than one layer, the vertical permeability above the horizontal (the geometric mean of x and y) in more than half the active cells (the facts resolution/grid/kv_above_kh_share and kv_over_kh_median). |
physics.transport.dispersivity_below_grid | info | The largest stated dispersivity below the grid’s own numerical dispersivity, half the median cell size, along an axis the active cells span (the facts resolution/grid/numerical_dispersivity_<axis>; Cartesian grids). |
physics.grid.zcorn_inverted | error | A corner-point cell’s bottom face above its top face (beyond 1e-6 depth slack). |
physics.grid.zcorn_layer_order | error | A deeper corner-point layer sitting above the layer over it on the same pillar. |
physics.grid.no_active_cells | error | No cell survives porosity, ACTNUM, and the minimum-pore-volume threshold. |
physics.grid.tops_cliff | warning | On a cartesian grid with no declared fault, neighbouring columns whose tops step by at least the thickness of a layer, so the layer’s two cells share no depth across the face. |
physics.grid.pinch_threshold_excessive | warning | A PINCH threshold that bridges a column’s stack of inactive cells (ACTNUM 0 or below the minimum pore volume) thicker than the median active layer. Silent on an all-active grid. |
physics.grid.radial_sector_incomplete | info | A radial grid with a single angular sector narrower than 15 degrees. |
physics.grid.fault_super_conductive | warning | Fault transmissibility multiplier above 100. |
physics.grid.nnc_magnitude | warning | Explicit NNC or override transmissibility beyond 1000x the largest neighbor-face transmissibility the grid and rock imply. |
physics.grid.nnc_between_neighbors | warning | An explicit NNC linking cells that already share a face (stands down when explicit connection edits are declared alongside). |
physics.grid.zero_thickness_layer_completed | warning | A layer with zero thickness in every column that wells complete through. |
physics.grid.depth_implausible | warning | Grid top deeper than 12000 m (39370 ft). |
physics.grid.thickness_implausible | warning | Thickest total column under 1 m (3.3 ft) at field scale. |
Why each check exists:
physics.rock.porosity_bounds
Porosity is a volume fraction; outside the unit interval, pore volumes go negative or exceed the rock that hosts them.
physics.rock.permeability_negative
Permeability is a non-negative material property; a negative value makes transmissibilities change sign and flow run against potential gradients. Zero-permeability barrier cells are legitimate.
physics.rock.porosity_implausible
Sandstone and carbonate top out near 0.45; diatomite reaches 0.45-0.70 (Belridge) and is the acknowledged exception. A whole field tighter than 1% stores nothing worth simulating (individual zero-porosity barriers stay legal).
physics.rock.permeability_implausible
Natural rock tops out near 1e5 mD and even engineered porous media near a few darcy-millions; a whole field under a microdarcy flows nothing on any simulation timescale.
physics.contacts.datum_above_surface
The sign slip of a test deck (EQUIL -3150 with a contact at -3320), which earlier read as a core-scale model and stood every band down; the bands now judge such a model, and this warning names the slip.
physics.stand_down.bands
A check that cannot judge a model says so once per compile rather than falling silent (62 corpus decks stood down without a word).
physics.stand_down.geometry
Makes the corner-point gap visible on 526 corpus decks until PetroScript computes their cell geometry.
physics.rock.compressibility_unstated
OPM Flow runs a model without ROCK with incompressible rock: its pore volume does not change with pressure (measured on SPE1 with ROCK removed). Test decks whose card stated no compressibility lost it silently; PetroScript never supplies a value.
physics.rock.compressibility_range
The softest unconsolidated sediment sits near 1e-3 1/bar; beyond a few times that the rock is a sponge and the pressure solution is dominated by an unphysical storage term.
physics.rock.reference_pressure_remote
Flow grows the pore volume from the reference pressure, so the run starts with that much more (or less) pore volume, and fluid in place, than the stated porosity gives. A porosity measured at the reference pressure makes it the model’s own (SPE5 states its porosity at 14.7 psia and starts 2.0% larger), so the row informs; the 2% is a tolerance on the model’s own number.
physics.rock.kv_above_kh
Layered rock conducts better along its layers than across them, and a permeability_x swapped with permeability_z reads this way. Rock that does conduct better vertically exists (two corpus decks state it on purpose), so the row informs.
physics.transport.dispersivity_below_grid
An upstream-weighted grid spreads a front by about half a cell on its own, so a smaller stated dispersivity is lost in it.
physics.grid.zcorn_inverted
The cell has negative volume and self-intersects; pore volumes and transmissibilities computed from it are garbage with plausible magnitudes.
physics.grid.zcorn_layer_order
Depth must be non-decreasing down every pillar; regressing layers interleave cells so that layer k+1 physically overlaps layer k and vertical flow connects the wrong rock.
physics.grid.no_active_cells
There is no reservoir left to simulate; every downstream computation acts on an empty set.
physics.grid.tops_cliff
The layer loses its lateral connection to itself and Flow joins each cell to the other column’s layers through non-neighbour connections: a stepped TOPS grid written for a dipping reservoir does this across most of its faces (one test grid cut 408 of its 672 x-faces into 1,254 NNCs). A dipping reservoir is written as corner-point geometry; a deliberate throw is declared as a fault.
physics.grid.pinch_threshold_excessive
PINCH item 1 generates a non-neighbour connection across inactive cells whose combined thickness is under the threshold (manual 6.3.175); it does not pinch thin active layers, and on an all-active grid it changes nothing. A threshold that bridges a thick inactive stack connects across a barrier the model itself states.
physics.grid.radial_sector_incomplete
All volumes and rates are silently scaled by angle/360 relative to the full cylinder — correct for a sector study, but the scaling should be a stated choice, not a surprise in the volumetrics.
physics.grid.fault_super_conductive
Conductive fault rock tops out around 10–100x the host; beyond that the fault is a super-conduit no geology provides, short-circuiting the field.
physics.grid.nnc_magnitude
The connection is an infinite-conductivity teleport between cells; besides being unphysical, one enormous off-band coefficient wrecks matrix conditioning.
physics.grid.nnc_between_neighbors
The NNC transmissibility adds to the existing neighbor face, double-counting the flow area — the pair is twice as connected as the geometry says.
physics.grid.zero_thickness_layer_completed
The completions connect to no rock there: the declared interval quietly contributes nothing, which usually means the layering and the completion table disagree.
physics.grid.depth_implausible
No producing reservoir sits below ~12 km — the deepest wells ever drilled barely reach it; a top this deep is almost always metres-vs-feet confusion.
physics.grid.thickness_implausible
A field-wide column under a metre is a seismic artifact, not a reservoir; core-scale models are exempt via the scale gate.
Wells and completions
Section titled “Wells and completions”| Code | Tier | What it checks |
|---|---|---|
physics.wells.completed_in_void | warning | Every completion of a well landing in cells with no active pore volume (zero porosity, inactive, or below the minimum-pore-volume threshold). |
physics.wells.bore_exceeds_cell | warning | Wellbore radius at or beyond the Peaceman equivalent radius r0 of a connected cell, when the skin keeps OPM’s denominator positive. |
physics.wells.short_circuit | warning | A producer and an injector completing the same cell. |
physics.wells.shared_cell_same_role | info | Two wells of one role completing the same cell with the schedule holding both open at the same time. |
physics.wells.rate_target_without_pressure_limit | info | A forecast oil-, water- or gas-rate target (a control, never a history record) that holds, while the well is open at a report step, no bottom-hole pressure limit, no tubing-head pressure limit through a lift table, and no liquid or reservoir-volume limit; a retarget before the step counts. The weakest limit of each well’s forecast rate controls is a fact (wells/<w>/pressure_limit). |
physics.wells.isolated_by_sealing | warning | A well completed only in cells whose every outward face is sealed by factor-zero (or ≤1e-9) face multipliers. |
physics.wells.completion_diameter_range | warning | Completion diameter outside 0.05–1.0 m (0.16–3.3 ft). |
physics.wells.reference_depth_remote | warning | Well BHP reference depth more than 1000 m (3281 ft) below the grid’s depth span. |
physics.completion.skin_infeasible | error | OPM’s well-index denominator, ln(r0/min(rw, r0)) + skin, at or below zero in any cell the completion connects, with r0 Peaceman’s equivalent radius for the cell’s own dimensions and permeabilities across the bore (Peaceman 1983, SPE-10528): dx, dy with kx, ky for a vertical connection; dy, dz along X; dx, dz along Y, dz thinned by NTG as OPM thins it. A stated pressure-equivalent radius (COMPDAT item 14) is r0 itself, as in OPM. A defaulted skin is 0; a stated connection factor is not judged. |
physics.completion.kh_inconsistent | warning | Explicit completion kh disagreeing with rock permeability times the completed interval by more than 100x in either direction. |
physics.completion.edit_misses_connection_factor | info | A ps.grid.Scale (by other than 1) or ps.grid.Assign of permeability_x, _y or _z over a cell where an open connection states its connection factor. |
Why each check exists:
physics.wells.completed_in_void
The well touches no reservoir, so it produces silently zero flow and any rate target on it is demanded from rock that is not there. Calibrated to W: the target shuts such a well and continues, and the upstream corpus tests that behaviour on purpose, so this is a supported state and not a malformed model.
physics.wells.bore_exceeds_cell
OPM computes ln(r0/min(rw, r0)) + skin: past r0 it clamps rw to r0, so only the skin is left in the denominator and Peaceman’s model no longer describes the connection. Flow runs it (a skin-5 witness ran), so it warns.
physics.wells.short_circuit
Injected fluid short-circuits straight into the producer within one cell: perfect sweep on paper, no displacement in fact. Coarse grids do put real pattern wells in one cell, so the message names both wells, the cell, and whether the schedule ever has the two open at the same moment — never-simultaneous is sequential use of a cell, not a short circuit.
physics.wells.shared_cell_same_role
Each takes the cell’s full connection factor, as if it were the cell’s only well, so how the two share the cell’s inflow is not represented. The corpus’s WAG pairs (SPE5, WAGHYSTR) share a cell in turn, a control or a status change shutting one as the other opens on the same date, and are not named; with no run behind it, two open at once informs. How far a producer stands from its nearest injector is a fact (wells/<w>/nearest_injector, cells_to_nearest_injector, Cartesian grids); the fixed 50 m floor between opposite roles is gone.
physics.wells.rate_target_without_pressure_limit
OPM Flow holds the rate down to its default bottom-hole pressure of 1 atm. Measured (2026.04, SPE1 with a water injector two cells from the producer): with no limit the producer fell to 14.7 psia and, by the run’s end, drew 21,396 stb/d of liquid at a water cut of 0.71, against 18,944 stb/d at a 1000 psia limit. Corpus decks state such targets on purpose, so it informs.
physics.wells.isolated_by_sealing
The well cannot exchange fluid with the rest of the grid; it produces only its own cells’ storage and then behaves erratically against its controls. Deliberately compartmentalized studies acknowledge.
physics.wells.completion_diameter_range
Wellbores outside [5 cm, 1 m] are outside any drilling program; the usual cause is a radius-vs-diameter or inch-vs-foot slip, which shifts every well index.
physics.wells.reference_depth_remote
Every reported BHP is corrected across a fictitious wellbore column, so limits and reports are systematically offset. Wellhead-referenced (shallow) datums are a sanctioned convention and stay silent; only the downward direction is judged.
physics.completion.skin_infeasible
The connection factor divides by this number, so at or below zero it is infinite or negative: ill-posed. At skin 0 with the bore at r0 Flow aborts (“Non-finite primary variable”); at skin -20 it runs with the inflow sign-inverted, a producer reporting a BHP above the reservoir while delivering its target. It is a question about each connected cell, not a constant: in a 10 m cell with a 0.3 m bore even skin -3 gives -0.42, while in a 10 km cell skin -8.5 still gives +0.99.
physics.completion.kh_inconsistent
Explicit kh is a legal override (test-derived kh, partial penetration), but a two-orders-of-magnitude self-contradiction between two descriptions of the same connection is a darcy-for-millidarcy class of slip. The band stays two-sided and this wide: a well test’s kh can stand from about a tenth of the rock’s to some fifty times it within one field, so the mD.m-vs-mD.ft slip (3.28x) lies inside what tests measure. A skin is judged only by skin_infeasible’s denominator: the +100 and -8 skins and the D-factor ceiling were a typical field’s, and are gone.
physics.completion.edit_misses_connection_factor
OPM Flow keeps a stated connection factor, so the edit moves the cell’s transmissibility to its neighbours and leaves the well’s inflow as stated. Measured (2026.04, SPE1, CTFAC at the producer’s cell): a stated factor of 100 stayed 100 with PERMX x10 over the cell; the factor Flow computes went from 10.61 to 32.96. A history-matching edit meant for the transmissibility alone is deliberate, so it informs.
Aquifers and boundaries
Section titled “Aquifers and boundaries”| Code | Tier | What it checks |
|---|---|---|
physics.aquifer.zero_compressibility | error | Analytic aquifer total compressibility of zero. |
physics.aquifer.no_active_connection | warning | Every cell an aquifer connects to is inactive or holds no pore volume. |
physics.aquifer.volume_implausible | info | A Fetkovich aquifer whose time constant, compressibility times water volume over productivity index (the fact aquifers/<n>/time_constant), is longer than the run (run_length_in_time_constants below 1). |
physics.aquifer.past_influence_table | warning or info | A Carter-Tracy aquifer whose dimensionless time at the run’s end (run_length_in_time_constants) is beyond its influence table’s last row: a warning on OPM Flow’s built-in table of an infinite aquifer, which ends at 10,000; an info row on a stated table. |
physics.aquifer.influence_table_kind | warning | An influence table whose dimensionless pressure falls as the dimensionless time rises, or whose rows between 0.01 and 0.1 (two at least) all follow the constant-pressure influx function’s short-time series within 3%. |
physics.aquifer.datum_inconsistent | warning | Aquifer datum pressure more than 90% (of the envelope magnitude) outside the hydrostatic envelope between the reservoir datum pressure and its water-gradient projection to the aquifer datum depth. |
physics.boundary.interior_face | error | A lab boundary condition declared on cells that do not lie on the named domain face (i/j/k equal to 1 or the grid extent). |
physics.thpres.undefined_region | warning | A threshold pressure referencing an equilibration region no cell of the region map declares (a model without a map has the single region 1). |
physics.thpres.no_shared_face | info | A threshold-pressure pair whose regions meet nowhere: no shared cell face, no face across which a fault throw or a stepped TOPS juxtaposes their cells (on a cartesian grid, from the cell depths), and no stated non-neighbour connection between them. It stands down on a corner-point grid with offset columns, or under a PINCH policy, where Flow may join cells this reading cannot see. |
Why each check exists:
physics.aquifer.zero_compressibility
The analytic drive term is proportional to total compressibility; at zero the aquifer can never deliver a barrel regardless of drawdown — it is an aquifer in name only.
physics.aquifer.no_active_connection
The aquifer exchanges water through its connection set; connected entirely to dead cells it can never exchange anything. Flow ignores each connection (“Connection to inactive cell … is ignored”) and runs, so the intended pressure support silently does not exist: a warning.
physics.aquifer.volume_implausible
Over such a run the aquifer does not deplete and acts as a constant-pressure boundary, which makes any depletion look supported. It is a modelling choice, so it informs; the row states both numbers.
physics.aquifer.past_influence_table
Flow extends the table’s last segment as a straight line. Past the built-in table that line leaves the infinite aquifer’s pressure function, which grows as half the logarithm of the time (9.86 against 6.16 at 100,000), so the pressure function and its slope are wrong there; a bounded aquifer’s own late-time function is a straight line, so a stated table only informs.
physics.aquifer.influence_table_kind
A Carter-Tracy aquifer reads its table as the pressure function at a constant influx rate, which never falls; the influx function at a constant pressure starts from the same 0.112 at 0.01 and then runs above it (0.404 against 0.315 at 0.1), so a table copied from the wrong one of the two classic tables reads this way. The 38 corpus tables are silent.
physics.aquifer.datum_inconsistent
The water column connecting reservoir and aquifer fixes their pressure relationship; a datum pressure far outside that envelope starts the pair violently out of equilibrium, and the first timesteps model the typo, not the aquifer.
physics.boundary.interior_face
An interior cell-cell interface is definitionally not a boundary; the condition would inject or withdraw fluid across a face that has rock on both sides.
physics.thpres.undefined_region
The intended barrier applies to nothing; Flow says the region values are not compatible with EQLNUM, ignores the pair and runs, so it warns.
physics.thpres.no_shared_face
The declared threshold can never act — legal and harmless, but the barrier it models is fiction and the author probably meant a different region pair.
Units and cross-object consistency
Section titled “Units and cross-object consistency”| Code | Tier | What it checks |
|---|---|---|
physics.units.system_suspect | warning | Either vote: (a) the surface densities, in both directions: an oil or water density inside the other system’s band (FIELD oil 28.1-68.7, water 59.3-81.2, gas 0.0031-0.2185 lb/ft3; METRIC oil 450-1100, water 950-1300, gas 0.05-3.5 kg/m3) and outside its own, with none reading as its own system (a gas density in both bands abstains, and a gas in the oil slot is not judged as oil); (b) in a METRIC deck, a datum gradient of 0.43-0.65 bar/m, where the FIELD hydrostatic gradient reads numerically, together with a datum deeper than 4800 or a pressure above 1500. |
Why each check exists:
physics.units.system_suspect
Numbers typed in the other unit system pass each band on their own and fail as a set. The surface densities are the sharpest vote: the two systems’ oil and water bands do not overlap. The gradient vote’s window was 0.35-0.55 and missed SPE1 labelled METRIC at 0.571.
Thermal
Section titled “Thermal”| Code | Tier | What it checks |
|---|---|---|
physics.thermal.below_absolute_zero | error | Initial reservoir temperature below -459.67 degF (FIELD) or -273.15 degC (METRIC). |
physics.thermal.inverted_profile | warning | A depth-temperature profile segment falling faster than -0.05 degC/m (-0.0275 degF/ft). |
physics.thermal.oil_viscosity_increases_with_temperature | error | Thermal oil-viscosity table strictly rising across the whole temperature span. |
physics.thermal.unsupported | error | physics.thermal holding anything other than a semantic thermal package (including thermal-conductivity region-pair coupling requested without one). |
Why each check exists:
physics.thermal.below_absolute_zero
Temperatures below absolute zero do not exist; every thermal property evaluated there is undefined.
physics.thermal.inverted_profile
Real geothermal inversions (permafrost, groundwater flow) are of order -0.01 degC/m; a gradient this steeply negative is a swapped depth/temperature column or a Celsius/Fahrenheit confusion.
physics.thermal.oil_viscosity_increases_with_temperature
Liquid oil thins with heat (Arrhenius behavior), never thickens; a rising table inverts the entire point of thermal recovery.
physics.thermal.unsupported
Thermal semantics flow through one typed package; anything else cannot be validated or lowered, and rendering it would emit an unchecked deck.
Target limitations
Section titled “Target limitations”A physics guard judges the reservoir. A target limitation judges the
simulator: the model is sound, states nothing impossible, and would run
somewhere — but the named target refuses or aborts on it. These codes carry
the target. prefix, fire at the warning tier, and acknowledge through the
same gate, because a deck authored for a target without the limitation is a
legitimate deck.
| Code | Tier | What it checks |
|---|---|---|
target.restart.field_group_wells | warning | An initial state that restarts from a previous run while any well sits in the root group — no group of its own, or a group named FIELD. Both spell the same WELSPECS token. |
target.thermal.multisegment_energy | warning | A thermal package in energy mode (not temperature-only) together with any multisegment well topology. |
target.keyword_ignored | info | A rendered directive the named target parses and does nothing with. |
Why each check exists:
target.restart.field_group_wells
OPM Flow rebuilds a restarted run’s wells from the groups its restart file records, and aborts while restoring a well whose parent group is FIELD: Internal error: unordered_map::at, measured on 2025.10 and 2026.04 alike, so it is a standing limitation rather than one release’s regression. Naming a group for each well is the whole fix; the physics does not change.
target.thermal.multisegment_energy
OPM Flow does not solve energy for multisegment wells: energy is not supported by multisegment well yet, raised from MultisegmentWell_impl.hpp on 2025.10 and 2026.04 alike, after which the solver fails to converge and the run stops. The combination is physically ordinary — a heated well completed in segments — so the model is not at fault; the simulator has not implemented it. Temperature-only thermal models are unaffected, because Flow refuses the energy equation specifically.
target.keyword_ignored
The deck carries the request faithfully and the run is unaffected; the issue exists so a study is not built on output the target never produces.
The construction-time layer beneath the guards
Section titled “The construction-time layer beneath the guards”The physics guards are the top of a two-layer defense. Beneath them,
construction-time validation owns type and structure: strict typed fields
reject strings-for-numbers and unit-less quantities at assignment;
positivity and sign checks hold on rates, dimensions, table entries,
initial pressures, dissolved and vaporized ratios by depth, bubble and dew
points by depth, and identifiers; PVT and relperm tables enforce monotone pressure and
saturation columns, non-empty families, and per-region family counts; and
phase gating ties every package, control, and table to the phases the
formulation actually declares. Those diagnostics carry their own domain
codes (fluids.*, relperm.*, grid.*, schedule.*, …) and are always
errors — the physics guards assume structurally valid input and judge only
whether the physics it describes can exist.
Acknowledging warnings
Section titled “Acknowledging warnings”| Code | Tier | What it checks |
|---|---|---|
physics.acknowledge.stale | error | Every code in the model’s acknowledged_warnings must currently fire as a warning on the model. |
Why each check exists:
physics.acknowledge.stale
An acknowledgment is a claim (“this model is deliberately unusual in this specific way”); once the weirdness is gone, the claim is false, and stale claims rot into acknowledge-everything boilerplate that defeats the tier system.
The model states its acknowledgments as acknowledged_warnings=[...], by
keyword or by address (model.set("acknowledged_warnings", [...])).
It accepts only warning-tier codes — unknown or error-tier codes are
refused by name when the model is made — and demotes each matching firing
warning to an informational issue:
import petroscript as ps
base = ps.Model( name="BASE", units="field", start="2020-01-01", grid=ps.grid.Cartesian(shape=(2, 2, 1), dx=500.0, dy=500.0, dz=40.0, top=2500.0), rock=ps.Rock(porosity=0.25, permeability=100.0, vertical_ratio=1.0), fluid=ps.fluid.OilWater( oil=ps.pvt.DeadOil(pressure=[14.7, 3500.0], oil_fvf=[1.06, 1.0], oil_viscosity=[1.0, 1.2]), water=ps.pvt.Water( reference_pressure=3000.0, fvf=1.0, compressibility=3.0e-6, viscosity=0.5, viscosibility=0.0, ), oil_surface_density=53.0, water_surface_density=64.0, ), relperm=[ps.relperm.OilWater(sw=[0.20, 0.80], krw=[0.0, 1.0], krow=[1.0, 0.0], pcow=[0.0, 0.0])], initial=ps.initial.Equilibrium( datum_depth=2520.0, datum_pressure=3000.0, oil_water_contact=2600.0, gas_oil_contact=0.0 ), wells=[ps.Well(name="PROD1", i=1, j=1)], schedule=ps.Schedule( report=[ps.Every(30.0)], events=[ ps.Event( "2020-01-01", ps.Perforate(well="PROD1", k=(1, 1), diameter=0.3), ps.Produce(well="PROD1", oil_rate=220.0, bhp_limit=1200.0), ) ], ),)
model = base.set({ "schedule/2020-01-01/PROD1/control": ps.Produce(well="PROD1", oil_rate=0.01, bhp_limit=1200.0), "schedule/report": [ps.Every(36500.0)], "acknowledged_warnings": ["physics.schedule.century_step"],})Without the acknowledged_warnings entry this model is still made — warnings
never block — but the century-scale step stays a warning in model.check().
With it, the warning is demoted to info. If the schedule is later shortened so
the warning no longer fires, the same entry is refused as a
physics.acknowledge.stale error (a ps.ModelError) until it is removed:
acknowledgments must stay true.
PetroScript is licensed under the Apache License 2.0. © 2026 Blauweiss EDV LLC. PetroScript by Blauweiss AI.For AI agents: llms.txt