pyrestoolbox 3.4.0__tar.gz → 3.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/PKG-INFO +1 -1
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyproject.toml +1 -1
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/brine/_lib_vle_engine.py +18 -8
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/brine/brine.py +6 -3
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/changelist.rst +39 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/gas.rst +241 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/matbal.rst +22 -3
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/nodal.rst +6 -6
- pyrestoolbox-3.5.0/pyrestoolbox/gas/_hydrate.py +513 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/gas/gas.py +2030 -2280
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/matbal/matbal.py +32 -8
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/nodal/nodal.py +4 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_harmonize.py +2 -2
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_pvt_class.py +1 -1
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_tables.py +23 -17
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/shared_fns/shared_fns.py +11 -8
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/simtools/simtools.py +23 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/bessel.rs +7 -3
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/lib.rs +0 -2
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/oil/density.rs +0 -46
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/oil/mod.rs +0 -31
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/spycher_pruess/mod.rs +3 -2
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/spycher_pruess/solubility.rs +801 -794
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vle/flash.rs +246 -427
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vle/mod.rs +127 -197
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/segment_gas.rs +9 -8
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/segment_oil.rs +5 -5
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/.github/workflows/build-wheels.yml +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/.gitignore +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/Cargo.lock +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/Cargo.toml +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/LICENSE +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/MANIFEST.in +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/README.rst +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/ResToolbox/privacy_policy.md +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/benchmark_rust_vs_python.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/build_pure_python.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/__init__.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/_accelerator.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/brine/__init__.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/brine/_lib_salting_library.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/classes/__init__.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/classes/classes.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/constants/__init__.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/constants/constants.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/dca/__init__.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/dca/dca.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/brine.rst +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/dca.rst +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/examples.ipynb +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/img/bot.png +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/img/bot_PVTO.png +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/img/bot_img.png +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/img/dry_gas.png +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/img/grid_sat_df.png +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/img/influence.png +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/img/properties_df.png +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/img/sgof.png +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/img/swof.png +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/layer.rst +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/library.rst +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/nodal_examples.ipynb +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/nodal_hydrate_demo.ipynb +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/oil.rst +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/recommend.rst +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/sensitivity.rst +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/simtools.rst +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/gas/__init__.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/layer/__init__.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/layer/layer.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/library/__init__.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/library/component_library.xlsx +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/library/library.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/matbal/__init__.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/nodal/__init__.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/__init__.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_compressibility.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_constants.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_correlations.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_density.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_rate.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_separator.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_utils.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/plyasunov/__init__.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/plyasunov/iapws_if97.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/plyasunov/plyasunov_model.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/plyasunov/water_properties.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/recommend/__init__.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/recommend/recommend.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/sensitivity/__init__.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/sensitivity/sensitivity.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/shared_fns/__init__.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/simtools/__init__.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/validate/__init__.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/validate/validate.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/setup.cfg +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/setup.py +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/critical_properties/mod.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/dca/hyperbolic.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/dca/mod.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/dca/ransac.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/gas_viscosity/mod.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/gwr.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/matbal/mod.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/matbal/objective.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/pseudopressure.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vle/alpha.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vle/bip.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vle/components.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vle/eos.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vle/fugacity.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vle/k_init.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vle/rachford_rice.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/friction.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/holdup_bb.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/holdup_gray.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/holdup_hb.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/holdup_wg.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/ift.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/mod.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/pvt_helpers.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/static_column.rs +0 -0
- {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/zfactor/mod.rs +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "maturin"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pyrestoolbox"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.5.0"
|
|
8
8
|
description = "pyResToolbox - A collection of Reservoir Engineering Utilities"
|
|
9
9
|
license = {text = "GPL-3.0-or-later"}
|
|
10
10
|
authors = [{name = "Mark W. Burgoyne", email = "mark.w.burgoyne@gmail.com"}]
|
|
@@ -2106,15 +2106,21 @@ class SWMultiComponentFlash:
|
|
|
2106
2106
|
# specialised ks models (Dubessy CO2, Akinfiev H2S, Li HC,
|
|
2107
2107
|
# Mao-Duan N2, Duan-Sun CO2) are applied in self.calc_gamma()
|
|
2108
2108
|
# on the Python side.
|
|
2109
|
-
|
|
2109
|
+
#
|
|
2110
|
+
# Restricted to framework='proposed': the Rust flash hardcodes the
|
|
2111
|
+
# MC-3 water alpha and the proposed-framework kij_AQ. The 'dropin'
|
|
2112
|
+
# and 'sw_original' frameworks use a salinity-dependent Soreide water
|
|
2113
|
+
# alpha and different kij_AQ correlations that Rust does not implement,
|
|
2114
|
+
# so they must take the Python path to avoid a silent downgrade.
|
|
2115
|
+
if _RUST_AVAILABLE and self.framework == 'proposed':
|
|
2110
2116
|
try:
|
|
2111
2117
|
gamma_arr = np.asarray(gamma, dtype=float) if gamma is not None \
|
|
2112
2118
|
else np.ones(self.nc)
|
|
2113
|
-
V, x_r, y_r = _rust.flash_tp_rust(
|
|
2119
|
+
V, x_r, y_r, conv_r = _rust.flash_tp_rust(
|
|
2114
2120
|
T_K, P_Pa, z.tolist(), list(self.names),
|
|
2115
2121
|
0.0, mode, gamma_arr.tolist(),
|
|
2116
2122
|
)
|
|
2117
|
-
return V, np.array(x_r), np.array(y_r),
|
|
2123
|
+
return V, np.array(x_r), np.array(y_r), conv_r
|
|
2118
2124
|
except (ImportError, AttributeError):
|
|
2119
2125
|
pass
|
|
2120
2126
|
|
|
@@ -2269,8 +2275,12 @@ class SWMultiComponentFlash:
|
|
|
2269
2275
|
salinity_method = 'explicit'
|
|
2270
2276
|
|
|
2271
2277
|
# Rust acceleration path: compute gamma in Python (correct ks models),
|
|
2272
|
-
# then use Rust flash_tp for the two flashes.
|
|
2273
|
-
|
|
2278
|
+
# then use Rust flash_tp for the two flashes. Restricted to
|
|
2279
|
+
# framework='proposed' — Rust only implements the proposed-framework
|
|
2280
|
+
# water alpha (MC-3) and kij_AQ; 'dropin'/'sw_original' would be
|
|
2281
|
+
# silently downgraded to 'proposed', so they take the Python path.
|
|
2282
|
+
if (_RUST_AVAILABLE and salinity_method == 'gamma_phi'
|
|
2283
|
+
and self.framework == 'proposed'):
|
|
2274
2284
|
try:
|
|
2275
2285
|
gamma_aq = None
|
|
2276
2286
|
if self.salinity > 0:
|
|
@@ -2281,11 +2291,11 @@ class SWMultiComponentFlash:
|
|
|
2281
2291
|
else [1.0] * self.nc
|
|
2282
2292
|
names_list = list(self.names)
|
|
2283
2293
|
|
|
2284
|
-
V_aq, x_aq_r, y_aq_r = _rust.flash_tp_rust(
|
|
2294
|
+
V_aq, x_aq_r, y_aq_r, conv_aq = _rust.flash_tp_rust(
|
|
2285
2295
|
T_K, P_Pa, z.tolist(), names_list,
|
|
2286
2296
|
self.salinity, 'AQ', gamma_list,
|
|
2287
2297
|
)
|
|
2288
|
-
V_na, x_na_r, y_na_r = _rust.flash_tp_rust(
|
|
2298
|
+
V_na, x_na_r, y_na_r, conv_na = _rust.flash_tp_rust(
|
|
2289
2299
|
T_K, P_Pa, z.tolist(), names_list,
|
|
2290
2300
|
self.salinity, 'NA', [1.0] * self.nc,
|
|
2291
2301
|
)
|
|
@@ -2296,7 +2306,7 @@ class SWMultiComponentFlash:
|
|
|
2296
2306
|
result = {
|
|
2297
2307
|
'x_aq': x_aq, 'y_na': y_na, 'K_true': K_true,
|
|
2298
2308
|
'V_aq': V_aq, 'V_na': V_na,
|
|
2299
|
-
'converged_aq':
|
|
2309
|
+
'converged_aq': conv_aq, 'converged_na': conv_na,
|
|
2300
2310
|
'component_names': self.names,
|
|
2301
2311
|
'salinity_method': salinity_method,
|
|
2302
2312
|
'vlle_warning': False,
|
|
@@ -967,9 +967,10 @@ class CO2_Brine_Mixture():
|
|
|
967
967
|
"""
|
|
968
968
|
if _RUST_AVAILABLE:
|
|
969
969
|
try:
|
|
970
|
-
xco2, yco2, yh2o, rhogas, gasz = _rust.co2_brine_solubility_rust(
|
|
970
|
+
xco2, yco2, yh2o, rhogas, gasz, conv = _rust.co2_brine_solubility_rust(
|
|
971
971
|
self.pBar, self.degC, self.ppm
|
|
972
972
|
)
|
|
973
|
+
self.converged = conv
|
|
973
974
|
self.x = np.array([xco2, 1.0 - xco2 - (self.xSalt if self.xSalt else 0.0)])
|
|
974
975
|
self.y = np.array([yco2, yh2o])
|
|
975
976
|
self.rhoGas = rhogas
|
|
@@ -1939,8 +1940,10 @@ class SoreideWhitson:
|
|
|
1939
1940
|
gas_ply = _VLE_TO_PLYASUNOV.get(gas_vle, gas_vle.upper())
|
|
1940
1941
|
vphi_eff_p1 += yi * _plyasunov_V_phi(gas_ply, tKel, Mpa_p1)
|
|
1941
1942
|
|
|
1942
|
-
|
|
1943
|
-
|
|
1943
|
+
# Garcia Eq. 18 at P+1, same algebraically reformulated (non-singular)
|
|
1944
|
+
# form as Step 3 — multiply top/bot through by M1*x1.
|
|
1945
|
+
numerator_p1 = MWWAT * x1 + self.x_total * mw_eff
|
|
1946
|
+
denom_p1 = self.x_total * vphi_eff_p1 + MWWAT * x1 / rho_brine_p1_gcc
|
|
1944
1947
|
rho_p1_gcc = numerator_p1 / denom_p1
|
|
1945
1948
|
else:
|
|
1946
1949
|
rho_p1_gcc = rho_brine_p1_gcc
|
|
@@ -1,3 +1,42 @@
|
|
|
1
|
+
Changelist in 3.5.0:
|
|
2
|
+
|
|
3
|
+
- **Gas non-Darcy & partial-penetration pseudoskins** — three new public functions in ``pyrestoolbox.gas`` plus two matching ``GasPVT`` convenience methods. Oilfield + metric unit support throughout.
|
|
4
|
+
|
|
5
|
+
- ``gas.gas_hvf_beta(k, method='FK' | 'JONES' | 'TCK', phi=0, metric=False)`` — Forchheimer high-velocity-flow coefficient β. Three correlations: ``'FK'`` (default, log-log fit of Firoozabadi & Katz 1979 JPT Feb, consolidated-rock β(k) chart), ``'JONES'`` (Jones 1987 SPE-16949), ``'TCK'`` (Tek, Coats, Katz 1962 JPT Jul, requires ``phi``). Returns β in 1/ft (or 1/m if ``metric=True``).
|
|
6
|
+
- ``gas.gas_non_darcy_skin(qg, k, h_perf, rw, mug, sg, krg=1.0, beta_method='FK', phi=0, metric=False)`` — returns ``{'beta', 'D', 'S_hvf'}`` where D uses the standard ``2.222e-15 · β · γg · k / (μg · h · rw)`` form (Jones 1987; Odeh, Moreland & Schueler 1975 JPT Dec). Output ``D`` is in day/MSCF (or day/sm3 if metric) and can be passed directly to ``gas_rate_radial(D=...)``. ``krg < 1`` evaluates β at the damaged-zone permeability ``k' = k·krg`` for a pessimistic S\ :sub:`hvf`.
|
|
7
|
+
- ``gas.gas_partial_penetration_skin(htot, htop, hbot, rw, kh_kv=10)`` — partial-penetration pseudoskin by direct evaluation of the Streltsova-Adams (1979) SPE-7486 analytical series. Bessel K\ :sub:`0` from ``scipy.special.k0``; vectorised summation to 20,000 terms (sub-millisecond). Warns when the series tail suggests incomplete convergence for very thin wellbores. Unit-agnostic — only ratios enter the formula, so inputs share any consistent length unit.
|
|
8
|
+
- ``GasPVT.non_darcy_skin(qg, p, degf, k, h_perf, rw, krg=1, beta_method='FK', phi=0)`` and ``GasPVT.partial_penetration_skin(htot, htop, hbot, rw, kh_kv=10)`` — the former auto-computes μ\ :sub:`g` from stored PVT state; both honour the ``GasPVT.metric`` flag.
|
|
9
|
+
|
|
10
|
+
18 new unit tests in ``test_gas.py`` (all three β correlations, metric round-trip, damaged-zone, series convergence, geometry validation, ``GasPVT`` delegation). 12 new doc-example tests in ``test_doc_examples.py`` pin every RST example value. Reference S\ :sub:`p` values verified against a 50,000-term direct evaluation of the Streltsova-Adams series.
|
|
11
|
+
|
|
12
|
+
- **PVTO export format fix** (``simtools.make_bot_og(pvto=True, export=True)``). The exported ``PVTO.INC`` placed Eclipse's ``/`` stem-terminator on every saturated row, prematurely closing each stem before its undersaturated continuation rows. A strict parser would then read each continuation row as an unset stem and either error or drop the data. The saturated row now omits ``/`` when undersaturated rows follow; the terminator moves to the LAST undersaturated row of the stem, matching the reference example in the Eclipse manual (``PVTO`` keyword). Stems with no undersaturated extension still carry ``/`` on the saturated row, and the final null-record ``/`` on its own line still terminates the table. Underlying ``usat`` data returned in the results dict was already correct — only the export layout changed.
|
|
13
|
+
|
|
14
|
+
- **Removed dead module** ``pyrestoolbox/oil/oil.py``. Pre-April-2026 monolith superseded by the ``_correlations.py`` / ``_density.py`` / ``_tables.py`` / etc. sub-modules. Nothing in the package or tests imported from it. No public-API change — ``from pyrestoolbox import oil`` and ``oil.<func>`` keep working via ``oil/__init__.py`` re-exports.
|
|
15
|
+
|
|
16
|
+
- **Brine framework correctness (Rust path)**. ``SoreideWhitson(framework='dropin')`` and ``framework='sw_original'`` were silently computed as ``'proposed'`` whenever the Rust accelerator was installed: the Rust flash hardcodes the proposed-framework MC-3 water alpha and kij\ :sub:`AQ`, with no framework parameter. The Rust dispatch in ``brine._lib_vle_engine`` (``flash_tp`` and ``calc_equilibrium``) is now gated on ``framework == 'proposed'``; the other two frameworks take the framework-aware Python path. Pure-Python results were always correct. Adds a regression test exercising both non-proposed frameworks.
|
|
17
|
+
|
|
18
|
+
- **Brine convergence flag (Rust path)**. ``flash_tp_rust`` and ``co2_brine_solubility_rust`` now return the convergence bool they compute, so ``SoreideWhitson``/``CO2_Brine_Mixture`` ``.converged`` (and the ``converged_aq``/``converged_na`` flash flags) report the real outcome instead of being hardcoded ``True`` when Rust is active.
|
|
19
|
+
|
|
20
|
+
- **Oil ``oil_harmonize`` default ``pbmethod`` unified to VALMC** (was ``VELAR``), matching ``oil_pbub`` / ``oil_rs`` / ``oil_co`` / ``OilPVT``. Previously ``oil_harmonize`` and the other oil functions returned mutually inconsistent Pb/Rsb on identical inputs. The deprecated ``OilPVT.from_harmonize`` default was aligned too. **Behaviour change**: default ``oil_harmonize`` output shifts for callers that relied on the old default (e.g. the ``rsb_frac`` returned when both ``pb`` and ``rsb`` are supplied). Pass ``pbmethod='VELAR'`` explicitly to retain the old behaviour.
|
|
21
|
+
|
|
22
|
+
- **Nodal HB VLP Rust/Python parity**. Hampson-Brill superficial-gas-velocity and gas-density constants in the Rust accelerator (``35.3741`` molar-volume factor, ``10.73`` vs ``10.732``, ``29.0`` vs ``28.97`` air MW) are aligned with the Python path, making all four VLP methods bit-exact between Rust and Python. The HB-oil/HB-gas parity tests are tightened from ``rtol=1e-3`` to ``1e-4``. Affected HB doc-example BHPs shifted by ~0.05–0.25% to the now-identical Rust/Python value (e.g. ``fbhp`` oil 1771.47 → 1770.58 psi); RST examples updated to match.
|
|
23
|
+
|
|
24
|
+
- **``simtools.rr_solver`` single-phase guard**. Single-phase feeds (all-liquid or all-vapor) previously fell through to the two-phase Nielsen-Lia solver and returned ``inf``/``nan`` with only a divide-by-zero warning. They are now detected up front and return the trivial split (V=0 or V=1); non-positive K-values raise ``ValueError``.
|
|
25
|
+
|
|
26
|
+
- **``nodal.fthp`` input validation**. ``fthp`` now validates ``well_type`` / ``vlpmethod`` / ``bhp`` at entry like the other public nodal functions, instead of only erroring transitively through the inner ``fbhp`` solve.
|
|
27
|
+
|
|
28
|
+
- **``validate_pe_inputs`` array safety**. The ``sg`` and inert-fraction checks are now array-safe (previously ``sg <= 0`` raised an ambiguous-truth-value error on array inputs).
|
|
29
|
+
|
|
30
|
+
- **Brine undersaturated-compressibility density** now uses the same algebraically reformulated, non-singular Garcia Eq. 18 as the saturated-density step (removes the ``xCO2 → 1`` singularity from the P+1 density used in ``Cf_usat``). Mathematically identical for ``xCO2 < 1``.
|
|
31
|
+
|
|
32
|
+
- **Removed dead Rust exports** ``oil_bo_mccain_rust`` and ``calc_equilibrium_rust`` (and their now-orphaned internals), which had no Python callers. New Rust-vs-Python parity tests added for ``gas_ponz2p`` and ``simtools.influence_tables`` — the two live accelerated paths that previously had no parity coverage.
|
|
33
|
+
|
|
34
|
+
- **``oil_matbal`` aquifer water influx**. New optional ``We`` parameter (cumulative aquifer influx in reservoir volume, rb | rm3) brings oil material balance to parity with ``gas_matbal``. The influx is subtracted from underground withdrawal before estimating OOIP (Havlena-Odeh ``F - We = N·[Eo + m·Eg + (1+m)·Efw]``) — feeding both the Python and Rust regression objectives — and a Water Drive Index (``'WDI'``) is added to ``drive_indices`` so the indices sum to 1 under water drive. Fully backward-compatible: with ``We`` omitted, ``WDI`` is all-zero and OOIP/DDI/SDI/CDI are unchanged.
|
|
35
|
+
|
|
36
|
+
- **Internal: hydrate code split out of ``gas.py``**. ``gas_hydrate``, ``HydrateResult``, the HFT/HFP/Østergaard helpers and their constants now live in ``pyrestoolbox/gas/_hydrate.py`` (≈480 lines carved off the ``gas.py`` monolith). Public API is unchanged — ``gas.gas_hydrate`` and ``gas.HydrateResult`` are re-exported. ``_hydrate`` imports ``gas_water_content`` lazily, so there is no circular import.
|
|
37
|
+
|
|
38
|
+
- 838 validation tests (up from 812 in 3.4.0).
|
|
39
|
+
|
|
1
40
|
Changelist in 3.4.0:
|
|
2
41
|
|
|
3
42
|
- **BREAKING — Brine metric default standardization**: ``CO2_Brine_Mixture`` and ``SoreideWhitson`` constructors now default to ``metric=False`` (oilfield units) to match ``brine_props`` and every other pyrestoolbox API. Previously they defaulted to ``metric=True``. Existing callers that relied on the old default must either pass ``metric=True`` explicitly or switch their input units to psia / degF. RST and notebook examples that relied on the default have been updated to pass ``metric=True`` explicitly.
|
|
@@ -138,6 +138,12 @@ Function List
|
|
|
138
138
|
- `pyrestoolbox.gas.gas_rate_linear`_
|
|
139
139
|
* - Gas Hydrate Prediction
|
|
140
140
|
- `pyrestoolbox.gas.gas_hydrate`_
|
|
141
|
+
* - Forchheimer HVF Coefficient (β)
|
|
142
|
+
- `pyrestoolbox.gas.gas_hvf_beta`_
|
|
143
|
+
* - Non-Darcy (HVF) Skin
|
|
144
|
+
- `pyrestoolbox.gas.gas_non_darcy_skin`_
|
|
145
|
+
* - Partial-Penetration Pseudoskin
|
|
146
|
+
- `pyrestoolbox.gas.gas_partial_penetration_skin`_
|
|
141
147
|
* - Gas PVT Wrapper
|
|
142
148
|
- `pyrestoolbox.gas.GasPVT`_
|
|
143
149
|
|
|
@@ -1414,6 +1420,228 @@ With reservoir P,T (gas equilibrated at reservoir, hydrate assessment at wellhea
|
|
|
1414
1420
|
True
|
|
1415
1421
|
|
|
1416
1422
|
|
|
1423
|
+
pyrestoolbox.gas.gas_hvf_beta
|
|
1424
|
+
=============================
|
|
1425
|
+
|
|
1426
|
+
.. code-block:: python
|
|
1427
|
+
|
|
1428
|
+
gas_hvf_beta(k, method='FK', phi=0.0, metric=False) -> float
|
|
1429
|
+
|
|
1430
|
+
Returns the Forchheimer high-velocity-flow (inertial) coefficient β, used in non-Darcy flow calculations. Three correlations are available. All return β in 1/ft (or 1/m when ``metric=True``) for permeability ``k`` in md.
|
|
1431
|
+
|
|
1432
|
+
.. list-table:: β correlations
|
|
1433
|
+
:widths: 8 25 20
|
|
1434
|
+
:header-rows: 1
|
|
1435
|
+
|
|
1436
|
+
* - method
|
|
1437
|
+
- Correlation
|
|
1438
|
+
- Source
|
|
1439
|
+
* - ``'FK'``
|
|
1440
|
+
- β = 2.172e10 · k⁻¹·²⁰¹
|
|
1441
|
+
- Log-log fit of Firoozabadi & Katz (1979) JPT Feb, pp.211-216 (SPE-6827) consolidated-rock β(k) chart. Default.
|
|
1442
|
+
* - ``'JONES'``
|
|
1443
|
+
- β = 6.15e10 · k⁻¹·⁵⁵
|
|
1444
|
+
- Jones, S.C. (1987) SPE-16949
|
|
1445
|
+
* - ``'TCK'``
|
|
1446
|
+
- β = 1.88e10 / (k¹·⁴⁷ · φ⁰·⁵³)
|
|
1447
|
+
- Tek, Coats, Katz (1962) JPT Jul, pp.799-806. Requires ``phi``.
|
|
1448
|
+
|
|
1449
|
+
.. list-table:: Inputs
|
|
1450
|
+
:widths: 10 15 40
|
|
1451
|
+
:header-rows: 1
|
|
1452
|
+
|
|
1453
|
+
* - Parameter
|
|
1454
|
+
- Type
|
|
1455
|
+
- Description
|
|
1456
|
+
* - k
|
|
1457
|
+
- float
|
|
1458
|
+
- Permeability (md). To evaluate β at a damaged-zone permeability, pass ``k' = k * krg``.
|
|
1459
|
+
* - method
|
|
1460
|
+
- string
|
|
1461
|
+
- ``'FK'`` (default), ``'JONES'``, or ``'TCK'``.
|
|
1462
|
+
* - phi
|
|
1463
|
+
- float
|
|
1464
|
+
- Porosity fraction. Required for ``method='TCK'``.
|
|
1465
|
+
* - metric
|
|
1466
|
+
- bool
|
|
1467
|
+
- If True, returns β in 1/m; else 1/ft. Defaults to False.
|
|
1468
|
+
|
|
1469
|
+
Examples:
|
|
1470
|
+
|
|
1471
|
+
.. code-block:: python
|
|
1472
|
+
|
|
1473
|
+
>>> gas.gas_hvf_beta(100.0) # FK, 100 md
|
|
1474
|
+
86071589.04028143
|
|
1475
|
+
>>> gas.gas_hvf_beta(100.0, method='JONES')
|
|
1476
|
+
48851186.4355433
|
|
1477
|
+
>>> gas.gas_hvf_beta(100.0, method='TCK', phi=0.25)
|
|
1478
|
+
45003847.531218514
|
|
1479
|
+
>>> gas.gas_hvf_beta(100.0, metric=True) # 1/m
|
|
1480
|
+
282387103.1505296
|
|
1481
|
+
|
|
1482
|
+
|
|
1483
|
+
pyrestoolbox.gas.gas_non_darcy_skin
|
|
1484
|
+
===================================
|
|
1485
|
+
|
|
1486
|
+
.. code-block:: python
|
|
1487
|
+
|
|
1488
|
+
gas_non_darcy_skin(qg, k, h_perf, rw, mug, sg, krg=1.0,
|
|
1489
|
+
beta_method='FK', phi=0.0, metric=False) -> dict
|
|
1490
|
+
|
|
1491
|
+
Returns the rate-dependent (high-velocity-flow) pseudoskin for a gas well. Computes β via ``gas_hvf_beta``, the non-Darcy coefficient D following Jones (1987) SPE-16949 / Odeh, Moreland, Schueler (1975) JPT Dec pp.1501-1504, and the skin S\ :sub:`hvf` = D · q\ :sub:`g`.
|
|
1492
|
+
|
|
1493
|
+
Formula (field units):
|
|
1494
|
+
|
|
1495
|
+
D [day/MSCF] = 2.222×10⁻¹⁵ · β · γ\ :sub:`g` · k / (μ\ :sub:`g` · h\ :sub:`perf` · r\ :sub:`w`)
|
|
1496
|
+
|
|
1497
|
+
where β is in 1/ft, k in md, μ\ :sub:`g` in cP, h\ :sub:`perf` and r\ :sub:`w` in ft.
|
|
1498
|
+
|
|
1499
|
+
.. list-table:: Inputs
|
|
1500
|
+
:widths: 10 15 40
|
|
1501
|
+
:header-rows: 1
|
|
1502
|
+
|
|
1503
|
+
* - Parameter
|
|
1504
|
+
- Type
|
|
1505
|
+
- Description
|
|
1506
|
+
* - qg
|
|
1507
|
+
- float
|
|
1508
|
+
- Gas rate (MSCF/D | sm3/D).
|
|
1509
|
+
* - k
|
|
1510
|
+
- float
|
|
1511
|
+
- Absolute permeability (md).
|
|
1512
|
+
* - h_perf
|
|
1513
|
+
- float
|
|
1514
|
+
- Perforated interval thickness (ft | m).
|
|
1515
|
+
* - rw
|
|
1516
|
+
- float
|
|
1517
|
+
- Wellbore radius (ft | m).
|
|
1518
|
+
* - mug
|
|
1519
|
+
- float
|
|
1520
|
+
- Gas viscosity at reservoir conditions (cP). Obtain from ``gas_ug`` or ``GasPVT.viscosity()``.
|
|
1521
|
+
* - sg
|
|
1522
|
+
- float
|
|
1523
|
+
- Gas specific gravity relative to air.
|
|
1524
|
+
* - krg
|
|
1525
|
+
- float
|
|
1526
|
+
- Gas relative permeability at critical oil saturation. If < 1.0, β is evaluated at the damaged-zone permeability ``k' = k * krg``, producing a more pessimistic S\ :sub:`hvf`. Defaults to 1.0 (undamaged).
|
|
1527
|
+
* - beta_method
|
|
1528
|
+
- string
|
|
1529
|
+
- ``'FK'`` | ``'JONES'`` | ``'TCK'`` (see `pyrestoolbox.gas.gas_hvf_beta`_). Defaults to ``'FK'``.
|
|
1530
|
+
* - phi
|
|
1531
|
+
- float
|
|
1532
|
+
- Porosity fraction. Required for ``beta_method='TCK'``.
|
|
1533
|
+
* - metric
|
|
1534
|
+
- bool
|
|
1535
|
+
- If True, inputs in (sm3/D, m, m) and D returned in day/sm3; else (MSCF/D, ft, ft) and D in day/MSCF. Defaults to False.
|
|
1536
|
+
|
|
1537
|
+
Returns a ``dict`` with keys:
|
|
1538
|
+
|
|
1539
|
+
.. list-table:: Returns
|
|
1540
|
+
:widths: 10 40
|
|
1541
|
+
:header-rows: 1
|
|
1542
|
+
|
|
1543
|
+
* - Key
|
|
1544
|
+
- Description
|
|
1545
|
+
* - ``'beta'``
|
|
1546
|
+
- Forchheimer coefficient (1/ft | 1/m)
|
|
1547
|
+
* - ``'D'``
|
|
1548
|
+
- Non-Darcy coefficient (day/MSCF | day/sm3). Suitable for passing directly to ``gas_rate_radial(D=...)``.
|
|
1549
|
+
* - ``'S_hvf'``
|
|
1550
|
+
- Rate-dependent skin (dimensionless).
|
|
1551
|
+
|
|
1552
|
+
Example (field units):
|
|
1553
|
+
|
|
1554
|
+
.. code-block:: python
|
|
1555
|
+
|
|
1556
|
+
>>> r = gas.gas_non_darcy_skin(qg=10000, k=100, h_perf=100, rw=0.33,
|
|
1557
|
+
... mug=0.025, sg=0.7)
|
|
1558
|
+
>>> round(r['beta'], 0)
|
|
1559
|
+
86071589.0
|
|
1560
|
+
>>> round(r['D'] * 1e5, 4) # D in units of 1e-5 day/MSCF
|
|
1561
|
+
1.6227
|
|
1562
|
+
>>> round(r['S_hvf'], 4)
|
|
1563
|
+
0.1623
|
|
1564
|
+
|
|
1565
|
+
Using damaged-zone β (krg < 1) and the TCK correlation:
|
|
1566
|
+
|
|
1567
|
+
.. code-block:: python
|
|
1568
|
+
|
|
1569
|
+
>>> r = gas.gas_non_darcy_skin(qg=10000, k=100, h_perf=100, rw=0.33,
|
|
1570
|
+
... mug=0.025, sg=0.7, krg=0.7,
|
|
1571
|
+
... beta_method='TCK', phi=0.22)
|
|
1572
|
+
>>> round(r['S_hvf'], 4)
|
|
1573
|
+
0.1534
|
|
1574
|
+
|
|
1575
|
+
Metric units (sm3/D, m) — same well, same skin:
|
|
1576
|
+
|
|
1577
|
+
.. code-block:: python
|
|
1578
|
+
|
|
1579
|
+
>>> r = gas.gas_non_darcy_skin(qg=283168.5, k=100, h_perf=30.48, rw=0.1006,
|
|
1580
|
+
... mug=0.025, sg=0.7, metric=True)
|
|
1581
|
+
>>> round(r['S_hvf'], 4)
|
|
1582
|
+
0.1622
|
|
1583
|
+
|
|
1584
|
+
|
|
1585
|
+
pyrestoolbox.gas.gas_partial_penetration_skin
|
|
1586
|
+
=============================================
|
|
1587
|
+
|
|
1588
|
+
.. code-block:: python
|
|
1589
|
+
|
|
1590
|
+
gas_partial_penetration_skin(htot, htop, hbot, rw, kh_kv=10.0) -> float
|
|
1591
|
+
|
|
1592
|
+
Returns the partial-penetration pseudoskin S\ :sub:`p` for a vertical well in a radial anisotropic reservoir, using the analytical series solution of Streltsova-Adams, T.D. (1979) "Pressure Drawdown in a Well with Limited Flow Entry," SPE J. Nov 1979, pp.1469-1476 (SPE-7486).
|
|
1593
|
+
|
|
1594
|
+
The series is summed directly (up to 20,000 terms, vectorised) with Bessel K₀ evaluated via ``scipy.special.k0``. A warning is emitted when the tail of the summation suggests the series has not fully converged (typical for very thin wellbores, i.e. r\ :sub:`w`/h\ :sub:`tot` ≪ 10⁻³ combined with small k\ :sub:`v`).
|
|
1595
|
+
|
|
1596
|
+
**All length inputs must share a consistent unit** (ft or m — only ratios enter the formula), so there is no separate ``metric`` flag on this function.
|
|
1597
|
+
|
|
1598
|
+
.. list-table:: Inputs
|
|
1599
|
+
:widths: 10 15 40
|
|
1600
|
+
:header-rows: 1
|
|
1601
|
+
|
|
1602
|
+
* - Parameter
|
|
1603
|
+
- Type
|
|
1604
|
+
- Description
|
|
1605
|
+
* - htot
|
|
1606
|
+
- float
|
|
1607
|
+
- Total formation thickness (no-flow to no-flow).
|
|
1608
|
+
* - htop
|
|
1609
|
+
- float
|
|
1610
|
+
- Distance from formation top to top of perforated interval.
|
|
1611
|
+
* - hbot
|
|
1612
|
+
- float
|
|
1613
|
+
- Distance from formation top to bottom of perforated interval.
|
|
1614
|
+
* - rw
|
|
1615
|
+
- float
|
|
1616
|
+
- Wellbore radius.
|
|
1617
|
+
* - kh_kv
|
|
1618
|
+
- float
|
|
1619
|
+
- Horizontal-to-vertical permeability anisotropy ratio (k\ :sub:`h`/k\ :sub:`v`). Defaults to 10.0. Set to 0 to treat vertical permeability as negligible (returns S\ :sub:`p` = 0).
|
|
1620
|
+
|
|
1621
|
+
Example (field units, ft):
|
|
1622
|
+
|
|
1623
|
+
.. code-block:: python
|
|
1624
|
+
|
|
1625
|
+
>>> gas.gas_partial_penetration_skin(htot=164.04, htop=32.81, hbot=147.64,
|
|
1626
|
+
... rw=0.3543, kh_kv=8.0)
|
|
1627
|
+
2.155398050852645
|
|
1628
|
+
|
|
1629
|
+
Metric call using meters — same well, dimensionless result is essentially identical:
|
|
1630
|
+
|
|
1631
|
+
.. code-block:: python
|
|
1632
|
+
|
|
1633
|
+
>>> gas.gas_partial_penetration_skin(htot=50.0, htop=10.0, hbot=45.0,
|
|
1634
|
+
... rw=0.108, kh_kv=8.0)
|
|
1635
|
+
2.155481748242132
|
|
1636
|
+
|
|
1637
|
+
Fully perforated interval (S\ :sub:`p` → 0):
|
|
1638
|
+
|
|
1639
|
+
.. code-block:: python
|
|
1640
|
+
|
|
1641
|
+
>>> round(gas.gas_partial_penetration_skin(htot=100, htop=0, hbot=100, rw=0.33), 10)
|
|
1642
|
+
0.0
|
|
1643
|
+
|
|
1644
|
+
|
|
1417
1645
|
pyrestoolbox.gas.GasPVT
|
|
1418
1646
|
========================
|
|
1419
1647
|
|
|
@@ -1495,3 +1723,16 @@ Using metric units (pressure in barsa, temperature in deg C):
|
|
|
1495
1723
|
>>> gpvt_m.density(137.9, 82.2)
|
|
1496
1724
|
97.36871728783241
|
|
1497
1725
|
|
|
1726
|
+
``GasPVT`` also exposes two skin helpers that reuse stored PVT state for viscosity:
|
|
1727
|
+
|
|
1728
|
+
.. code-block:: python
|
|
1729
|
+
|
|
1730
|
+
>>> gpvt = gas.GasPVT(sg=0.70)
|
|
1731
|
+
>>> r = gpvt.non_darcy_skin(qg=10000, p=3000, degf=200,
|
|
1732
|
+
... k=100, h_perf=100, rw=0.33, krg=0.7)
|
|
1733
|
+
>>> round(r['S_hvf'], 4)
|
|
1734
|
+
0.3044
|
|
1735
|
+
>>> round(gpvt.partial_penetration_skin(htot=50, htop=10, hbot=45,
|
|
1736
|
+
... rw=0.108, kh_kv=8), 4)
|
|
1737
|
+
2.1555
|
|
1738
|
+
|
|
@@ -192,13 +192,13 @@ pyrestoolbox.matbal.oil_matbal
|
|
|
192
192
|
.. code-block:: python
|
|
193
193
|
|
|
194
194
|
oil_matbal(p, Np, degf, api=0, sg_sp=0, sg_g=0, pb=0, rsb=0,
|
|
195
|
-
Rp=None, Wp=None, Wi=None, Gi=None,
|
|
195
|
+
Rp=None, Wp=None, Wi=None, Gi=None, We=None,
|
|
196
196
|
Bw=1.0, m=0, cf=0, sw_i=0, cw=0,
|
|
197
197
|
rsmethod='VELAR', bomethod='MCAIN',
|
|
198
198
|
zmethod='DAK', cmethod='PMC', metric=False,
|
|
199
199
|
pvt_table=None, regress=None) -> OilMatbalResult
|
|
200
200
|
|
|
201
|
-
Havlena-Odeh oil material balance for OOIP estimation. Computes underground withdrawal (F), oil expansion (Eo), gas cap expansion (Eg), and formation/water compressibility (Efw) terms at each pressure step.
|
|
201
|
+
Havlena-Odeh oil material balance for OOIP estimation. Computes underground withdrawal (F), oil expansion (Eo), gas cap expansion (Eg), and formation/water compressibility (Efw) terms at each pressure step. When cumulative aquifer influx ``We`` is supplied it is subtracted from the withdrawal first (``F - We = N·[Eo + m*Eg + (1+m)*Efw]``); OOIP is the mean of ``(F - We)/(Eo + m*Eg + (1+m)*Efw)`` across valid steps. Drive indices (DDI, SDI, CDI, WDI) are computed at each step.
|
|
202
202
|
|
|
203
203
|
.. list-table:: Inputs
|
|
204
204
|
:widths: 10 15 40
|
|
@@ -243,6 +243,9 @@ Havlena-Odeh oil material balance for OOIP estimation. Computes underground with
|
|
|
243
243
|
* - Gi
|
|
244
244
|
- array-like, optional
|
|
245
245
|
- Cumulative gas injection (scf | sm3). Default all zeros
|
|
246
|
+
* - We
|
|
247
|
+
- array-like, optional
|
|
248
|
+
- Cumulative aquifer water influx in reservoir volume (rb | rm3). Subtracted from withdrawal before estimating OOIP and surfaced as the 'WDI' water-drive index. No metric conversion (already a reservoir volume). Default all zeros
|
|
246
249
|
* - Bw
|
|
247
250
|
- float
|
|
248
251
|
- Water FVF (rb/stb | rm3/sm3, default 1.0)
|
|
@@ -304,7 +307,7 @@ Havlena-Odeh oil material balance for OOIP estimation. Computes underground with
|
|
|
304
307
|
- Formation and water compressibility term at each step
|
|
305
308
|
* - drive_indices
|
|
306
309
|
- dict
|
|
307
|
-
- Drive index fractions at each step: 'DDI' (depletion), 'SDI' (segregation/gas cap), 'CDI' (compaction/water). Each maps to np.ndarray
|
|
310
|
+
- Drive index fractions at each step: 'DDI' (depletion), 'SDI' (segregation/gas cap), 'CDI' (compaction/expansion), 'WDI' (water/aquifer influx). Each maps to np.ndarray. 'WDI' is all-zero when no ``We`` is supplied
|
|
308
311
|
* - p
|
|
309
312
|
- np.ndarray
|
|
310
313
|
- Pressure array used
|
|
@@ -330,6 +333,22 @@ Examples:
|
|
|
330
333
|
>>> r.drive_indices['DDI'][1]
|
|
331
334
|
0.7108509458427899
|
|
332
335
|
|
|
336
|
+
Water-drive Example (aquifer influx ``We``):
|
|
337
|
+
|
|
338
|
+
.. code-block:: python
|
|
339
|
+
|
|
340
|
+
>>> r = matbal.oil_matbal(
|
|
341
|
+
... p=[4000, 3500, 3000, 2500],
|
|
342
|
+
... Np=[0, 1e6, 3e6, 6e6],
|
|
343
|
+
... degf=220, api=35, sg_sp=0.75,
|
|
344
|
+
... pb=3500, rsb=500, cf=3e-6, sw_i=0.2, cw=3e-6,
|
|
345
|
+
... We=[0, 3e5, 1.2e6, 3.0e6]
|
|
346
|
+
... )
|
|
347
|
+
>>> r.ooip
|
|
348
|
+
58621028.243056096
|
|
349
|
+
>>> r.drive_indices['WDI'][-1]
|
|
350
|
+
0.4055063920332815
|
|
351
|
+
|
|
333
352
|
Regression Example (optimizing m and cf):
|
|
334
353
|
|
|
335
354
|
.. code-block:: python
|
|
@@ -499,7 +499,7 @@ Gas well:
|
|
|
499
499
|
>>> from pyrestoolbox import nodal
|
|
500
500
|
>>> c = nodal.Completion(tid=2.441, length=10000, tht=100, bht=200)
|
|
501
501
|
>>> nodal.fbhp(thp=500, completion=c, vlpmethod='HB', well_type='gas', qg_mmscfd=5.0, gsg=0.65, cgr=10, qw_bwpd=10, api=45, oil_vis=1.0)
|
|
502
|
-
|
|
502
|
+
954.8384864703888
|
|
503
503
|
|
|
504
504
|
Oil well:
|
|
505
505
|
|
|
@@ -507,7 +507,7 @@ Oil well:
|
|
|
507
507
|
|
|
508
508
|
>>> c = nodal.Completion(tid=2.441, length=8000, tht=100, bht=180)
|
|
509
509
|
>>> nodal.fbhp(thp=200, completion=c, vlpmethod='HB', well_type='oil', qt_stbpd=2000, gor=800, wc=0.3, gsg=0.65, pb=2500, rsb=500, sgsp=0.65, api=35)
|
|
510
|
-
|
|
510
|
+
1770.5840097037972
|
|
511
511
|
|
|
512
512
|
Oil well using OilPVT object:
|
|
513
513
|
|
|
@@ -516,7 +516,7 @@ Oil well using OilPVT object:
|
|
|
516
516
|
>>> from pyrestoolbox import oil
|
|
517
517
|
>>> opvt = oil.OilPVT(api=35, sg_sp=0.65, pb=2500, rsb=500)
|
|
518
518
|
>>> nodal.fbhp(thp=200, completion=c, vlpmethod='HB', well_type='oil', oil_pvt=opvt, qt_stbpd=2000, gor=800, wc=0.3, gsg=0.65)
|
|
519
|
-
|
|
519
|
+
1771.3518436635964
|
|
520
520
|
|
|
521
521
|
Deviated well using WellSegment:
|
|
522
522
|
|
|
@@ -525,7 +525,7 @@ Deviated well using WellSegment:
|
|
|
525
525
|
>>> segs = [nodal.WellSegment(md=5000, id=2.441, deviation=0), nodal.WellSegment(md=5000, id=2.441, deviation=45)]
|
|
526
526
|
>>> c_dev = nodal.Completion(segments=segs, tht=100, bht=200)
|
|
527
527
|
>>> nodal.fbhp(thp=500, completion=c_dev, vlpmethod='HB', well_type='gas', qg_mmscfd=5.0, gsg=0.65, cgr=10, qw_bwpd=10, api=45, oil_vis=1.0)
|
|
528
|
-
|
|
528
|
+
926.7968375529219
|
|
529
529
|
|
|
530
530
|
.. note::
|
|
531
531
|
|
|
@@ -854,14 +854,14 @@ Examples:
|
|
|
854
854
|
>>> from pyrestoolbox import nodal
|
|
855
855
|
>>> c = nodal.Completion(tid=2.441, length=10000, tht=100, bht=200)
|
|
856
856
|
>>> nodal.fbhp(thp=500, completion=c, vlpmethod='HB', well_type='gas', qg_mmscfd=5.0, gsg=0.65, cgr=10, qw_bwpd=10, api=45, oil_vis=1.0)
|
|
857
|
-
|
|
857
|
+
954.8384864703888
|
|
858
858
|
|
|
859
859
|
Comparing all four VLP methods for the same gas well:
|
|
860
860
|
|
|
861
861
|
.. code-block:: python
|
|
862
862
|
|
|
863
863
|
>>> nodal.fbhp(thp=500, completion=c, vlpmethod='HB', well_type='gas', qg_mmscfd=5.0, gsg=0.65, cgr=10, qw_bwpd=10, api=45, oil_vis=1.0)
|
|
864
|
-
|
|
864
|
+
954.8384864703888
|
|
865
865
|
>>> nodal.fbhp(thp=500, completion=c, vlpmethod='WG', well_type='gas', qg_mmscfd=5.0, gsg=0.65, cgr=10, qw_bwpd=10, api=45, oil_vis=1.0)
|
|
866
866
|
1172.8626065704736
|
|
867
867
|
>>> nodal.fbhp(thp=500, completion=c, vlpmethod='GRAY', well_type='gas', qg_mmscfd=5.0, gsg=0.65, cgr=10, qw_bwpd=10, api=45, oil_vis=1.0)
|