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.
Files changed (123) hide show
  1. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/PKG-INFO +1 -1
  2. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyproject.toml +1 -1
  3. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/brine/_lib_vle_engine.py +18 -8
  4. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/brine/brine.py +6 -3
  5. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/changelist.rst +39 -0
  6. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/gas.rst +241 -0
  7. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/matbal.rst +22 -3
  8. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/nodal.rst +6 -6
  9. pyrestoolbox-3.5.0/pyrestoolbox/gas/_hydrate.py +513 -0
  10. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/gas/gas.py +2030 -2280
  11. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/matbal/matbal.py +32 -8
  12. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/nodal/nodal.py +4 -0
  13. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_harmonize.py +2 -2
  14. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_pvt_class.py +1 -1
  15. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_tables.py +23 -17
  16. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/shared_fns/shared_fns.py +11 -8
  17. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/simtools/simtools.py +23 -0
  18. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/bessel.rs +7 -3
  19. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/lib.rs +0 -2
  20. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/oil/density.rs +0 -46
  21. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/oil/mod.rs +0 -31
  22. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/spycher_pruess/mod.rs +3 -2
  23. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/spycher_pruess/solubility.rs +801 -794
  24. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vle/flash.rs +246 -427
  25. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vle/mod.rs +127 -197
  26. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/segment_gas.rs +9 -8
  27. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/segment_oil.rs +5 -5
  28. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/.github/workflows/build-wheels.yml +0 -0
  29. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/.gitignore +0 -0
  30. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/Cargo.lock +0 -0
  31. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/Cargo.toml +0 -0
  32. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/LICENSE +0 -0
  33. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/MANIFEST.in +0 -0
  34. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/README.rst +0 -0
  35. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/ResToolbox/privacy_policy.md +0 -0
  36. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/benchmark_rust_vs_python.py +0 -0
  37. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/build_pure_python.py +0 -0
  38. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/__init__.py +0 -0
  39. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/_accelerator.py +0 -0
  40. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/brine/__init__.py +0 -0
  41. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/brine/_lib_salting_library.py +0 -0
  42. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/classes/__init__.py +0 -0
  43. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/classes/classes.py +0 -0
  44. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/constants/__init__.py +0 -0
  45. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/constants/constants.py +0 -0
  46. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/dca/__init__.py +0 -0
  47. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/dca/dca.py +0 -0
  48. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/brine.rst +0 -0
  49. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/dca.rst +0 -0
  50. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/examples.ipynb +0 -0
  51. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/img/bot.png +0 -0
  52. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/img/bot_PVTO.png +0 -0
  53. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/img/bot_img.png +0 -0
  54. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/img/dry_gas.png +0 -0
  55. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/img/grid_sat_df.png +0 -0
  56. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/img/influence.png +0 -0
  57. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/img/properties_df.png +0 -0
  58. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/img/sgof.png +0 -0
  59. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/img/swof.png +0 -0
  60. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/layer.rst +0 -0
  61. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/library.rst +0 -0
  62. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/nodal_examples.ipynb +0 -0
  63. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/nodal_hydrate_demo.ipynb +0 -0
  64. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/oil.rst +0 -0
  65. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/recommend.rst +0 -0
  66. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/sensitivity.rst +0 -0
  67. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/docs/simtools.rst +0 -0
  68. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/gas/__init__.py +0 -0
  69. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/layer/__init__.py +0 -0
  70. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/layer/layer.py +0 -0
  71. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/library/__init__.py +0 -0
  72. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/library/component_library.xlsx +0 -0
  73. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/library/library.py +0 -0
  74. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/matbal/__init__.py +0 -0
  75. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/nodal/__init__.py +0 -0
  76. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/__init__.py +0 -0
  77. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_compressibility.py +0 -0
  78. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_constants.py +0 -0
  79. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_correlations.py +0 -0
  80. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_density.py +0 -0
  81. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_rate.py +0 -0
  82. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_separator.py +0 -0
  83. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/oil/_utils.py +0 -0
  84. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/plyasunov/__init__.py +0 -0
  85. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/plyasunov/iapws_if97.py +0 -0
  86. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/plyasunov/plyasunov_model.py +0 -0
  87. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/plyasunov/water_properties.py +0 -0
  88. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/recommend/__init__.py +0 -0
  89. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/recommend/recommend.py +0 -0
  90. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/sensitivity/__init__.py +0 -0
  91. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/sensitivity/sensitivity.py +0 -0
  92. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/shared_fns/__init__.py +0 -0
  93. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/simtools/__init__.py +0 -0
  94. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/validate/__init__.py +0 -0
  95. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/pyrestoolbox/validate/validate.py +0 -0
  96. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/setup.cfg +0 -0
  97. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/setup.py +0 -0
  98. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/critical_properties/mod.rs +0 -0
  99. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/dca/hyperbolic.rs +0 -0
  100. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/dca/mod.rs +0 -0
  101. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/dca/ransac.rs +0 -0
  102. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/gas_viscosity/mod.rs +0 -0
  103. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/gwr.rs +0 -0
  104. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/matbal/mod.rs +0 -0
  105. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/matbal/objective.rs +0 -0
  106. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/pseudopressure.rs +0 -0
  107. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vle/alpha.rs +0 -0
  108. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vle/bip.rs +0 -0
  109. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vle/components.rs +0 -0
  110. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vle/eos.rs +0 -0
  111. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vle/fugacity.rs +0 -0
  112. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vle/k_init.rs +0 -0
  113. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vle/rachford_rice.rs +0 -0
  114. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/friction.rs +0 -0
  115. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/holdup_bb.rs +0 -0
  116. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/holdup_gray.rs +0 -0
  117. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/holdup_hb.rs +0 -0
  118. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/holdup_wg.rs +0 -0
  119. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/ift.rs +0 -0
  120. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/mod.rs +0 -0
  121. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/pvt_helpers.rs +0 -0
  122. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/vlp/static_column.rs +0 -0
  123. {pyrestoolbox-3.4.0 → pyrestoolbox-3.5.0}/src/zfactor/mod.rs +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyrestoolbox
3
- Version: 3.4.0
3
+ Version: 3.5.0
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Rust
6
6
  Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "pyrestoolbox"
7
- version = "3.4.0"
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
- if _RUST_AVAILABLE:
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), True
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
- if _RUST_AVAILABLE and salinity_method == 'gamma_phi':
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': True, 'converged_na': True,
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
- numerator_p1 = 1.0 + self.x_total * mw_eff / (MWWAT * x1)
1943
- denom_p1 = self.x_total * vphi_eff_p1 / (MWWAT * x1) + 1.0 / rho_brine_p1_gcc
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. OOIP is estimated as the mean of F/(Eo + m*Eg + (1+m)*Efw) across valid steps. Drive indices (DDI, SDI, CDI) are computed at each 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
- 952.6868477414688
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
- 1771.4717888847196
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
- 1772.2397895054948
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
- 923.092017723091
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
- 952.6868477414688
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
- 952.6868477414688
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)