3.4.0
-
BREAKING — Brine metric default standardization:
CO2_Brine_MixtureandSoreideWhitsonconstructors now default tometric=False(oilfield units) to matchbrine_propsand every other pyrestoolbox API. Previously they defaulted tometric=True. Existing callers that relied on the old default must either passmetric=Trueexplicitly or switch their input units to psia / degF. RST and notebook examples that relied on the default have been updated to passmetric=Trueexplicitly. -
nodal.outflow_curve parameter unification:
n_rateshas been renamed ton_pointsto matchipr_curve/operating_point.n_ratesremains accepted as a deprecated alias (takes precedence when both are passed) — existing callers keep working without changes. -
Type hints on public APIs:
nodal(fbhp / fthp / outflow_curve / ipr_curve / operating_point),oil(oil_co/bt return types, OilPVT constructor + methods, oil_rate_radial/linear), anddca(arps_, duong_, eur, fit_*, ratio_forecast, forecast) public signatures now carry type annotations. IDE autocomplete and static analysis now work out of the box for the primary user surface.matbal/simtools/plyasunovtype-hint backfill deferred. -
Rust-vs-Python parity harness: 63 new parametrized tests added to
test_rust_acceleration.py. Coverage:- Nodal gas VLP: 4 methods × 6 (THP, rate) points on a vertical well; WG/BB × 2 points on a deviated well (45-degree lower segment).
- Nodal oil VLP: 4 methods × 5 (THP, rate) points on a vertical well; WG/BB × 2 points on a deviated well.
- SoreideWhitson: pure CO2 across 4 (P, T) × 3 salinity points; sour-gas mix (CO2 + H2S + N2) at 2 points; natural-gas-only at 2 points.
Purpose is prophylactic — catches future one-sided edits between Python and Rust. Tolerance is
RTOL_MEDIUM = 1e-4. -
Rust HB-oil VLP bugfix (correctness). Three dimensional bugs in
src/vlp/segment_oil.rs(HB oil only — WG/GRAY/BB oil were coded correctly):min_lformula (rho_g * 62.37 / (rho_g * 62.37 + lsg * 62.37)simplified torho_g_lbft3 / (rho_g_lbft3 + lsg_SG)) mixed lb/cuft with dimensionless SG. Forced ~35% minimum liquid holdup at low rate when Python computed ~2%. Dominant contributor to the divergence.rho_avgaveraged gas vs stock-tank oil density, not the oil+water mixture density that includes live-oil McCain correction and water cut.ulsuperficial liquid velocity used stock-tank volumetric flow (ql * 5.615 / 86400 / area) instead of reservoir-conditions volumetric (mflow_l / rho_l / area). Missed the live-oil expansion / water-cut weighting.
Combined effect was up to ~75% over-prediction of BHP for HB oil wells at low rate / low THP. Python path was always correct; bug was isolated to the Rust accelerator. The
hb_holduphelper signature changed from takinglsg(implicit62.4 * lsginternally) to takingrho_ldirectly; gas-segment callers updated to pass62.4 * lsg_locto preserve prior behaviour. Parity harness drift reduced from 75% to <0.1% on the affected grid. -
Nodal
operating_pointnon-monotonic VLP handling. HB oil VLP curves can be non-monotonic at very low rate (spurious near-shut-in high BHP from holdup correlations). The previous bisection bracketed[min_rate, AOF]and failed when both endpoints had the same sign despite a crossing existing in between. Replaced with a scan-then-bisect: sample 25 rates, locate all sign changes in the error function, and bisect in the highest-rate bracket — the physical operating point. Setsconverged=Falseif no sign change is found. -
HB oil doc-example values updated. Three expected values changed due to the Rust HB-oil bugfix (Python values unchanged, Rust values now match Python):
fbhp(thp=200, ..., vlpmethod='HB', well_type='oil', qt_stbpd=2000, ...): 2271.72 psi → 1771.47 psifbhpwithoil_pvt=opvt: 2273.72 psi → 1772.24 psioperating_point(HB oil, thp=200, reservoir pr=3000): rate 1391.4 → 2019.0 stb/d, bhp 2206.3 → 1778.5 psi
RST and notebook examples updated to match the corrected values.
-
nodal.fthp: New reverse-solve function.
fthp(bhp, completion, ...)returns the tubing head pressure that produces the specified BHP under the given VLP correlation. Wrapsbisect_solveoverfbhp, accepts the same flow/well parameters asfbhp, and has matching units/metric handling. Users no longer need to hand-roll a bisection for wellhead back-calculation workflows. -
nodal.fbhp
return_profile=True: New kwarg. When enabled,fbhpreturns aNodalResultwith per-segment-boundarymd,tvd, andparrays (plus scalarbhp) instead of just the bottom-hole scalar. Exposes the wellbore pressure traverse without forking the internal segment march. Metric-aware outputs. -
nodal.operating_point extensions:
- New
injection=Falsekwarg, forwarded to internalfbhpandoutflow_curvecalls so injection wells can be solved directly throughoperating_point. Previouslyinjection=Truewas honoured only by directfbhpcalls. - New
convergedkey in the returnedNodalResult.Truewhen the VLP/IPR bisection succeeded,Falsewhen it fell back torate=0, bhp=pr(no intersection). Surfaces a condition that previously looked like a plausible zero-rate answer.
- New
-
nodal.outflow_curve dict key: Returned
NodalResultnow carries both'rate'and'rates'entries (same list).'rate'matchesipr_curveandoperating_point;'rates'is kept for backward compatibility. -
SoreideWhitson framework / salinity_method exposed: New
framework('proposed'|'sw_original'|'dropin') andsalinity_method('gamma_phi'|'embedded'|'explicit'|'sechenov'|'auto') constructor kwargs, forwarded to the VLE engine. Defaults unchanged ('proposed'+'gamma_phi'). Combiningframework='proposed'withsalinity_method='embedded'now emits a warning because the engine falls back togamma_phifor theproposedkij set. -
Brine
ppm/wtconflict detection:brine_props,CO2_Brine_Mixture, andSoreideWhitsonnow raiseValueError("Supply either ... not both.")when both aliases are passed. Previously one silently won with no feedback. -
Oil API cleanup:
- Removed private-helper re-exports
_cofb_mccain,_perrine_co_sat,_resolve_pb_rsb,_build_bot_tables,_format_bot_resultsfrompyrestoolbox.oilpublic namespace. Still reachable viapyrestoolbox.oil._tables/._density/._compressibilityfor advanced users;simtools.make_bot_ogupdated internally. - Dead imports removed across
_compressibility,_correlations,_density,_harmonize,_tablessub-files (11 symbols total). - Valko-McCain (2003) coefficient matrices for
sg_st_gasandoil_rs_stextracted to_constants.pywith paper citations, per CLAUDE.md named-constants rule.
- Removed private-helper re-exports
-
Oil documentation sync:
docs/oil.rstupdated —oil_denoparameter listed assg_o(matches code; was incorrectlysg_sto).make_bot_ogresult-dict table now documentsvis_frac(was previously omitted despite being returned). -
DCA internals: 20 previously inline magic numbers extracted to named constants at the top of
dca.py(Arps b-grid 0.05/0.96/0.01, Duong trap bounds and curve_fit bounds, logistic fit bounds, hyperbolic numerical floor)._build_decline_resulthelper deduplicates R-squared/residual/DeclineResult construction across the six_fit_*helpers (~60 lines removed). -
726 validation tests (up from 716 in 3.3.0). New coverage for
fthproundtrip,fbhppressure-traverse return,operating_point.converged,SoreideWhitsonframework/salinity_method validation, and the threeppm/wtconflict raises.