pyrestoolbox 3.8.4__tar.gz → 3.8.6__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 (152) hide show
  1. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/Cargo.lock +1 -1
  2. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/Cargo.toml +1 -1
  3. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/PKG-INFO +6 -5
  4. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/README.rst +1 -1
  5. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyproject.toml +5 -4
  6. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/changelist.rst +12 -0
  7. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/nodal.rst +1 -1
  8. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/simtools.rst +2 -0
  9. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/nodal/nodal.py +78 -41
  10. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/simtools/_aquifer.py +11 -3
  11. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/setup.cfg +4 -1
  12. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/setup.py +4 -4
  13. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/gwr.rs +83 -59
  14. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/pseudopressure.rs +72 -113
  15. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/vlp/constants.rs +6 -0
  16. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/vlp/march.rs +46 -15
  17. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/vlp/mod.rs +12 -12
  18. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/vlp/static_column.rs +20 -4
  19. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/.github/complexity-baseline.json +0 -0
  20. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/.github/scripts/check_complexity.py +0 -0
  21. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/.github/workflows/build-wheels.yml +0 -0
  22. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/.github/workflows/tests.yml +0 -0
  23. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/.gitignore +0 -0
  24. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/LICENSE +0 -0
  25. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/MANIFEST.in +0 -0
  26. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/ResToolbox/privacy_policy.md +0 -0
  27. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/build_pure_python.py +0 -0
  28. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/clippy.toml +0 -0
  29. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/mcp/Dockerfile +0 -0
  30. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/mcp/README.md +0 -0
  31. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/mcp/pyproject.toml +0 -0
  32. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/mcp/pyrestoolbox_mcp/__init__.py +0 -0
  33. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/mcp/pyrestoolbox_mcp/serialize.py +0 -0
  34. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/mcp/pyrestoolbox_mcp/server.py +0 -0
  35. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/mcp/tests/test_server.py +0 -0
  36. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/__init__.py +0 -0
  37. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/_accelerator.py +0 -0
  38. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/__init__.py +0 -0
  39. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/_lib_dielectric.py +0 -0
  40. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/_lib_maoduan_viscosity.py +0 -0
  41. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/_lib_pitzer_params.py +0 -0
  42. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/_lib_salting_library.py +0 -0
  43. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/_lib_vle_engine.py +0 -0
  44. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/appelo_volumes.py +0 -0
  45. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/brine.py +0 -0
  46. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/iapws_viscosity.py +0 -0
  47. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/jones_dole_viscosity.py +0 -0
  48. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/kestin_nacl_viscosity.py +0 -0
  49. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/pr_vphi.py +0 -0
  50. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/viscosity_route.py +0 -0
  51. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/vphi_route.py +0 -0
  52. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/classes/__init__.py +0 -0
  53. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/classes/classes.py +0 -0
  54. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/constants/__init__.py +0 -0
  55. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/constants/constants.py +0 -0
  56. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/dca/__init__.py +0 -0
  57. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/dca/dca.py +0 -0
  58. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/brine.rst +0 -0
  59. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/dca.rst +0 -0
  60. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/examples.ipynb +0 -0
  61. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/gas.rst +0 -0
  62. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/img/bot.png +0 -0
  63. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/img/bot_PVTO.png +0 -0
  64. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/img/bot_img.png +0 -0
  65. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/img/dry_gas.png +0 -0
  66. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/img/grid_sat_df.png +0 -0
  67. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/img/influence.png +0 -0
  68. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/img/properties_df.png +0 -0
  69. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/img/sgof.png +0 -0
  70. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/img/swof.png +0 -0
  71. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/index.rst +0 -0
  72. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/layer.rst +0 -0
  73. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/library.rst +0 -0
  74. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/matbal.rst +0 -0
  75. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/nodal_examples.ipynb +0 -0
  76. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/nodal_hydrate_demo.ipynb +0 -0
  77. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/oil.rst +0 -0
  78. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/plyasunov.rst +0 -0
  79. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/recommend.rst +0 -0
  80. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/sensitivity.rst +0 -0
  81. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/gas/__init__.py +0 -0
  82. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/gas/_hydrate.py +0 -0
  83. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/gas/gas.py +0 -0
  84. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/layer/__init__.py +0 -0
  85. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/layer/layer.py +0 -0
  86. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/library/__init__.py +0 -0
  87. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/library/component_library.xlsx +0 -0
  88. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/library/library.py +0 -0
  89. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/matbal/__init__.py +0 -0
  90. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/matbal/matbal.py +0 -0
  91. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/nodal/__init__.py +0 -0
  92. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/__init__.py +0 -0
  93. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_compressibility.py +0 -0
  94. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_constants.py +0 -0
  95. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_correlations.py +0 -0
  96. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_density.py +0 -0
  97. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_harmonize.py +0 -0
  98. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_pvt_class.py +0 -0
  99. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_rate.py +0 -0
  100. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_separator.py +0 -0
  101. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_tables.py +0 -0
  102. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_utils.py +0 -0
  103. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/plyasunov/__init__.py +0 -0
  104. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/plyasunov/iapws_if97.py +0 -0
  105. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/plyasunov/plyasunov_model.py +0 -0
  106. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/plyasunov/water_properties.py +0 -0
  107. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/recommend/__init__.py +0 -0
  108. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/recommend/recommend.py +0 -0
  109. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/sensitivity/__init__.py +0 -0
  110. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/sensitivity/sensitivity.py +0 -0
  111. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/shared_fns/__init__.py +0 -0
  112. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/shared_fns/shared_fns.py +0 -0
  113. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/simtools/__init__.py +0 -0
  114. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/simtools/_decks.py +0 -0
  115. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/simtools/_pvt_tables.py +0 -0
  116. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/simtools/_relperm.py +0 -0
  117. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/simtools/_vfp.py +0 -0
  118. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/simtools/simtools.py +0 -0
  119. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/validate/__init__.py +0 -0
  120. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/pyrestoolbox/validate/validate.py +0 -0
  121. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/bessel.rs +0 -0
  122. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/brine_visc/mod.rs +0 -0
  123. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/brine_visc/salt.rs +0 -0
  124. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/brine_visc/water.rs +0 -0
  125. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/critical_properties/mod.rs +0 -0
  126. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/dca/hyperbolic.rs +0 -0
  127. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/dca/mod.rs +0 -0
  128. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/dca/ransac.rs +0 -0
  129. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/gas_viscosity/mod.rs +0 -0
  130. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/lib.rs +0 -0
  131. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/matbal/mod.rs +0 -0
  132. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/matbal/objective.rs +0 -0
  133. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/oil/density.rs +0 -0
  134. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/oil/mod.rs +0 -0
  135. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/spycher_pruess/mod.rs +0 -0
  136. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/spycher_pruess/solubility.rs +0 -0
  137. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/vle/alpha.rs +0 -0
  138. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/vle/bip.rs +0 -0
  139. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/vle/components.rs +0 -0
  140. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/vle/eos.rs +0 -0
  141. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/vle/flash.rs +0 -0
  142. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/vle/fugacity.rs +0 -0
  143. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/vle/k_init.rs +0 -0
  144. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/vle/mod.rs +0 -0
  145. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/vle/rachford_rice.rs +0 -0
  146. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/vlp/friction.rs +0 -0
  147. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/vlp/holdup_bb.rs +0 -0
  148. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/vlp/holdup_gray.rs +0 -0
  149. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/vlp/holdup_wg.rs +0 -0
  150. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/vlp/ift.rs +0 -0
  151. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/vlp/pvt_helpers.rs +0 -0
  152. {pyrestoolbox-3.8.4 → pyrestoolbox-3.8.6}/src/zfactor/mod.rs +0 -0
@@ -152,7 +152,7 @@ dependencies = [
152
152
 
153
153
  [[package]]
154
154
  name = "pyrestoolbox-native"
155
- version = "3.8.4"
155
+ version = "3.8.6"
156
156
  dependencies = [
157
157
  "pyo3",
158
158
  "rug",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "pyrestoolbox-native"
3
- version = "3.8.4"
3
+ version = "3.8.6"
4
4
  edition = "2021"
5
5
  license = "GPL-3.0-or-later"
6
6
  description = "Rust acceleration extensions for pyResToolbox"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyrestoolbox
3
- Version: 3.8.4
3
+ Version: 3.8.6
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+)
@@ -9,10 +9,11 @@ Requires-Dist: numpy
9
9
  Requires-Dist: scipy
10
10
  Requires-Dist: pandas
11
11
  Requires-Dist: tabulate
12
- Requires-Dist: ilt-inversion
13
- Requires-Dist: mpmath
14
- Requires-Dist: gmpy2
15
12
  Requires-Dist: openpyxl
13
+ Requires-Dist: ilt-inversion ; extra == 'aquifer'
14
+ Requires-Dist: mpmath ; extra == 'aquifer'
15
+ Requires-Dist: gmpy2 ; extra == 'aquifer'
16
+ Provides-Extra: aquifer
16
17
  License-File: LICENSE
17
18
  Summary: pyResToolbox - A collection of Reservoir Engineering Utilities
18
19
  Keywords: restoolbox,petroleum,reservoir
@@ -64,7 +65,7 @@ All public PVT, flow rate, and simulation table functions support both oilfield
64
65
  Rust Acceleration (Optional)
65
66
  ----------------------------
66
67
 
67
- pyResToolbox includes optional Rust-compiled extensions that accelerate computationally intensive algorithms. When the compiled extension is present and loadable, these functions run automatically through Rust with no API changes. When the extension is unavailable, all functions fall back silently to the pure Python implementation.
68
+ pyResToolbox includes optional Rust-compiled extensions that accelerate computationally intensive algorithms. When the compiled extension is present and loadable, these functions run automatically through Rust with no API changes. When the extension is unavailable, all functions fall back silently to the pure Python implementation. The one exception is ``simtools.influence_tables``, whose pure-Python fallback needs the optional ``aquifer`` extra (``pip install 'pyrestoolbox[aquifer]'``).
68
69
 
69
70
  **Accelerated functions:**
70
71
 
@@ -39,7 +39,7 @@ All public PVT, flow rate, and simulation table functions support both oilfield
39
39
  Rust Acceleration (Optional)
40
40
  ----------------------------
41
41
 
42
- pyResToolbox includes optional Rust-compiled extensions that accelerate computationally intensive algorithms. When the compiled extension is present and loadable, these functions run automatically through Rust with no API changes. When the extension is unavailable, all functions fall back silently to the pure Python implementation.
42
+ pyResToolbox includes optional Rust-compiled extensions that accelerate computationally intensive algorithms. When the compiled extension is present and loadable, these functions run automatically through Rust with no API changes. When the extension is unavailable, all functions fall back silently to the pure Python implementation. The one exception is ``simtools.influence_tables``, whose pure-Python fallback needs the optional ``aquifer`` extra (``pip install 'pyrestoolbox[aquifer]'``).
43
43
 
44
44
  **Accelerated functions:**
45
45
 
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "pyrestoolbox"
7
- version = "3.8.4"
7
+ version = "3.8.6"
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"}]
@@ -21,13 +21,14 @@ dependencies = [
21
21
  "scipy",
22
22
  "pandas",
23
23
  "tabulate",
24
- "ilt-inversion",
25
- "mpmath",
26
- "gmpy2",
27
24
  "openpyxl",
28
25
  ]
29
26
  readme = "README.rst"
30
27
 
28
+ [project.optional-dependencies]
29
+ # Pure-Python fallback for simtools.influence_tables (the Rust extension needs none of these)
30
+ aquifer = ["ilt-inversion", "mpmath", "gmpy2"]
31
+
31
32
  [project.urls]
32
33
  Homepage = "https://github.com/mwburgoyne/pyResToolbox"
33
34
 
@@ -1,3 +1,15 @@
1
+ Changelist in 3.8.6:
2
+
3
+ - **SIMTOOLS: ``influence_tables`` Rust path now holds the precision the inversion needs (results move).** The Rust Gaver-Wynn-Rho inversion evaluates the Van Everdingen-Hurst transform with its own MPFR Bessel functions, and those carried less precision than GWR needs (about 2.1M digits). The series-to-asymptotic switch was fixed at x = 25, where the asymptotic expansion is good to only about 22 digits; the K-series ran with half the guard bits its cancellation needs; pi in the asymptotic prefactors and Euler's constant in the K0 series were f64 or 50-digit constants; and the I1 asymptotic expansion had a sign error. The switch now depends on the working precision, the guard bits match the cancellation, all constants are MPFR, and the I1 sign is corrected. Against a reference converged to 1e-14, the worst point on a 126-point table (ReD 1.5-20, tD 0.01-200) is now 2.2e-5 at M=7 (was 4.5e-5), 1.4e-8 at M=12 (was 1.6e-4), 3.2e-11 at M=18 (was 6.7e-3) and 2e-16 at M=32 (ReD 1.5 at tD 0.044 returned 20.07 against 0.2175), the same convergence as the pure-Python path. At the default M=7 the README example table (ReD 1.5-1000) moves by up to 4.6e-5 relative (ReD 1.5, tD 0.027: 0.172801 to 0.172809), 6e-7 on average. Run time is unchanged or a little shorter (121 against 138 ms for that table at M=7).
4
+
5
+ - **PACKAGING: ``ilt-inversion``, ``mpmath`` and ``gmpy2`` are now an optional extra (``pip install 'pyrestoolbox[aquifer]'``).** Only ``simtools.influence_tables`` uses them, and only on its pure-Python path; the Rust extension in every prebuilt wheel does the inverse Laplace transform and Bessel functions itself in MPFR. ``import pyrestoolbox.simtools`` no longer loads ``ilt`` or ``mpmath``. Without the Rust extension and without the extra, ``influence_tables`` raises ``ImportError`` naming the extra; every other function is unaffected. Existing environments keep working, since upgrading does not uninstall the three packages.
6
+
7
+ Changelist in 3.8.5:
8
+
9
+ - **NODAL: gas VLP uses the ``gas_pvt`` Z-factor and viscosity methods (results move when a GasPVT is passed).** ``fbhp``, ``fthp``, ``outflow_curve``, ``operating_point`` and the simtools VFP tables took only the gas SG and Sutton/Wichert-Aziz pseudo-criticals from a ``GasPVT``; the march always ran Hall-Yarborough Z with Lee-Gonzalez-Eakin viscosity, so ``zmethod='BNS'`` (or the GasPVT default, DAK with PMC) was silently ignored, as were H2 and He (which raised a warning). The march now evaluates Z and viscosity exactly as ``gas_pvt.z()`` and ``gas_pvt.viscosity()`` do, at every step and in the zero-rate static column, in Python and Rust (the Rust march builds the same Z/viscosity evaluator as ``gas_dmp``, so every method stays accelerated; the two paths agree to 1e-9 relative). Calls without ``gas_pvt`` are bit-identical. Example (THP 1000 psia, 5 MMscf/d, 100 bbl/d water, 5000 ft of 2.441 in tubing, 80-200 degF, SG 0.65), Beggs-Brill BHP: 1475.3 psia before, 1459.3 with ``GasPVT(sg=0.65)`` (DAK/PMC), 1508.2 with ``zmethod='BNS'``; WG 1444.8, 1444.1, 1446.2. Beggs-Brill moves most because the distributed-to-segregated boundary sits mid-well here and the gradient steps 27% across it. The pure-Python fallback is about 15 times slower with a ``gas_pvt`` (about 40 ms per ``fbhp``), since each step calls ``gas_z`` and ``gas_ug``. No documented example passes a ``gas_pvt`` to the VLP functions, so none moves; one nodal test that asserted a sweet ``GasPVT`` equals the ``gsg``-only answer now compares an HY/SUT ``GasPVT`` (within 4e-5).
10
+
11
+ - **NODAL: gas VLP results now approach the dry-gas answer continuously as the liquid rate goes to zero.** With no liquid every method returns the single-phase gas BHP, but a vanishing liquid rate did not: in a 5000 ft, 2.441 in well at 1000 psia THP and 5 MMscf/d (dry gas 1232 psia for all four methods), 1e-6 bbl/d of water gave WG 1294, GRAY 1243 and BB 1429 psia, and BB BHP fell as water rose from 0.001 to 1 bbl/d. The causes are in the correlations' low-liquid limits: the Woldesemayat-Ghajar drift-flux void fraction tends to u_sg/(u_sg + u_gm) because the drift velocity does not depend on the amount of liquid, leaving a stagnant liquid holdup u_gm/(u_sg + u_gm) at any liquid rate; Gray's holdup tends to exp(A); and Beggs-Brill holdup scales as lambda^0.58, so its friction parameter y = lambda/HL^2 grows without bound and the two-phase friction multiplier peaks near lambda = 1e-9. Hagedorn-Brown, whose holdup is floored at lambda, was already continuous. The gas segment march now blends each segment's gradient linearly between the method's own zero-liquid gradient and its two-phase gradient while the no-slip liquid fraction is below 1e-3 (``_LOW_LIQ_LAMBDA``, Rust ``LOW_LIQ_LAMBDA``). At zero liquid and at lambda >= 1e-3 results are unchanged; in between they are continuous and BHP rises monotonically with liquid rate. In the example, 1 bbl/d of water now gives WG 1237.5 (was 1298.5), GRAY 1233.3 (1245.8), BB 1241.2 (1335.7) and HB 1232.0 (1232.3) psia; 10 bbl/d gives WG 1300.8 (1312.7), GRAY 1263.3 (1269.2), BB 1324.9 (1338.9), HB 1234.7 (1235.3). Gas wells with a liquid-to-gas ratio above roughly 3 bbl/MMscf at flowing conditions, and every oil-well march, are unaffected. No frozen baseline or documented example moves.
12
+
1
13
  Changelist in 3.8.4:
2
14
 
3
15
  - **GAS: associated-gas hydrocarbon pseudo-criticals for BNS (``ag``).** Burgoyne, Nielsen & Stanko (2025) fitted two hydrocarbon Tc/Pc correlations, for gas condensates and for associated gas; only the condensate one was exposed. Every gas function that takes ``he`` (except ``gas_sg``, ``gas_hydrate`` and the recommenders, which use no critical properties) now also takes ``ag`` (keyword, appended last): ``gas_tc_pc``, ``gas_z``, ``gas_ug``, ``gas_cg``, ``gas_bg``, ``gas_den``, ``gas_thermal``, ``gas_ponz2p``, ``gas_grad2sg``, ``gas_dmp``, ``gas_rate_radial``, ``gas_rate_linear``, ``GasPVT`` and ``gas_matbal``. ``ag=True`` makes ``cmethod='BNS'`` return the associated-gas values (SG 0.75: Tc 397.7 against 401.2 degR, Pc 653.9 against 663.4 psia), and the hydrocarbon-inert BIPs follow the selected Tc, as in the regression. Other cmethods ignore it and a user ``tc``/``pc`` takes precedence. The resolved values reach the Rust paths through the existing hydrocarbon Tc/Pc override, so the Rust code is unchanged. With ``ag=True``, results match the reference BNS implementation (``AG=True``) to 5e-15 in Z and viscosity and 7e-13 Btu/lb-mol in enthalpy; with ``ag=False`` (the default) every result is bit-identical to 3.8.3 on both paths.
@@ -426,7 +426,7 @@ Returns flowing bottom hole pressure (psia, or barsa if metric=True) using the s
426
426
  - 'gas' or 'oil'
427
427
  * - gas_pvt
428
428
  - GasPVT
429
- - Gas PVT object. If provided, extracts gas composition (sg, co2, h2s, n2, h2, he) and method selections for IPR calculations
429
+ - Gas PVT object. If provided, the gas-well VLP march evaluates Z and gas viscosity with its methods and composition (as ``gas_pvt.z()`` and ``gas_pvt.viscosity()``: DAK with PMC by default, or HY or BNS as configured, impurities and H2/He included), and IPR calculations use the same. Without it the march uses Hall-Yarborough Z on Sutton pseudo-criticals of ``gsg`` with Lee-Gonzalez-Eakin viscosity
430
430
  * - oil_pvt
431
431
  - OilPVT
432
432
  - Oil PVT object. If provided for oil wells, extracts api, sgsp, pb, rsb
@@ -152,6 +152,8 @@ pyrestoolbox.simtools.influence_tables
152
152
 
153
153
  Solves Van Everdingin & Hurst Constant Terminal Rate solution via inverse Laplace transform and optionally writes out ECLIPSE styled AQUTAB include file.
154
154
 
155
+ The Rust extension (in every prebuilt wheel) does the inversion with no extra packages. Without it, the pure-Python fallback needs the optional ``aquifer`` extra (``ilt-inversion``, ``mpmath``, ``gmpy2``): ``pip install 'pyrestoolbox[aquifer]'``. Calling ``influence_tables`` on the pure-Python path without them raises ``ImportError``.
156
+
155
157
  Returns a tuple of;
156
158
  1. Dimensionless time list
157
159
  2. list of lists of dimensionless pressures at each dimensionless time for each dimensionless radius
@@ -62,6 +62,7 @@ from pyrestoolbox.constants import (BAR_TO_PSI, PSI_TO_BAR, degc_to_degf, degf_t
62
62
  D_PER_SM3_TO_D_PER_MSCF, D_PER_MSCF_TO_D_PER_SM3,
63
63
  STB_TO_SM3, SM3_TO_STB)
64
64
  import pyrestoolbox.gas as gas
65
+ from pyrestoolbox.gas.gas import _rust_cmethod
65
66
  import pyrestoolbox.oil as oil
66
67
  from pyrestoolbox.brine.viscosity_route import brine_viscosity as _brine_viscosity
67
68
  from pyrestoolbox._accelerator import RUST_AVAILABLE as _RUST_AVAILABLE, rust_accelerated
@@ -273,6 +274,12 @@ _GRAY_ND_COEF = 205.0 # Diameter number coefficient in A
273
274
  _GRAY_ROUGH_K = 28.5 # Effective roughness coefficient
274
275
  _GRAY_R_THRESH = 0.007 # R threshold for roughness interpolation
275
276
  _GRAY_SP_LIQ_FRAC = 1e-6 # v_sg/v_m below this is single-phase liquid (dry roughness)
277
+ # Below this no-slip liquid fraction the two-phase gradient is blended
278
+ # linearly toward the method's own zero-liquid gradient (weight lambda/_LOW_LIQ_LAMBDA).
279
+ # WG drift-flux and Gray holdup tend to finite values as liquid vanishes and
280
+ # Beggs-Brill's friction parameter y = lambda/HL^2 grows without bound, so
281
+ # without the blend a trace of liquid moved dry-gas BHP by up to 16%.
282
+ _LOW_LIQ_LAMBDA = 1e-3
276
283
  _GRAY_ROUGH_FLOOR = 2.77e-5 # Minimum effective roughness (ft)
277
284
 
278
285
  # ============================================================================
@@ -372,31 +379,25 @@ class _FlowInputs:
372
379
  gsg: float = 0.65
373
380
  vis_frac: float = 1.0
374
381
  rsb_frac: float = 1.0
375
- tc: Optional[float] = None # pseudo-critical T (deg R); None -> Sutton from gsg in the march
376
- pc: Optional[float] = None # pseudo-critical P (psia); None -> Sutton from gsg in the march
382
+ # Gas Z/viscosity spec from GasPVT (_gas_pvt_zspec); None -> Hall-Yarborough
383
+ # on Sutton pseudo-criticals of gsg with Lee-Gonzalez-Eakin viscosity
384
+ zspec: Optional[tuple] = None
377
385
 
378
386
 
379
- def _gas_pvt_tc_pc(gas_pvt):
380
- """Mixture pseudo-criticals for the VLP march from a GasPVT object.
387
+ def _gas_pvt_zspec(gas_pvt):
388
+ """Z-factor and viscosity specification for the VLP march from a GasPVT.
381
389
 
382
- The march runs Hall-Yarborough on Sutton pseudo-criticals of the total-gas
383
- sg. User-supplied tc/pc are honoured as given; otherwise, when the object
384
- carries CO2/H2S/N2, Sutton + Wichert-Aziz is applied so impurities reach the
385
- Z-factor as they already do in ipr_curve. Sweet gas returns (None, None) so
386
- the march path is untouched. BNS-style tc/pc are hydrocarbon-only and are
387
- not usable with a single-pseudo-component Z-factor, hence the SUT call here.
390
+ Returns (zmethod, cmethod, sg, [co2, h2s, n2, h2, he], tc, pc) with the
391
+ object's resolved methods and effective critical properties, so the march
392
+ evaluates Z and viscosity exactly as gas_pvt.z() and gas_pvt.viscosity()
393
+ do (Python via gas_z/gas_ug, Rust via the same GasState as gas_dmp). PMC
394
+ travels as 'SUT' with its already-resolved tc/pc, which gas_z treats as a
395
+ mixture override, as the Rust batch paths do.
388
396
  """
389
- if getattr(gas_pvt, '_user_tc_pc', False):
390
- return gas_pvt.tc, gas_pvt.pc
391
- if gas_pvt.h2 > 0 or getattr(gas_pvt, 'he', 0) > 0:
392
- warnings.warn(
393
- "VLP correlations use a Hall-Yarborough Z-factor with Sutton + Wichert-Aziz "
394
- "pseudo-criticals; the H2 and He fractions on gas_pvt are ignored in the wellbore march.",
395
- RuntimeWarning, stacklevel=3)
396
- if gas_pvt.co2 > 0 or gas_pvt.h2s > 0 or gas_pvt.n2 > 0:
397
- return gas.gas_tc_pc(gas_pvt.sg, co2=gas_pvt.co2, h2s=gas_pvt.h2s,
398
- n2=gas_pvt.n2, cmethod='SUT')
399
- return None, None
397
+ return (gas_pvt.zmethod.name, _rust_cmethod(gas_pvt.cmethod), float(gas_pvt.sg),
398
+ [float(gas_pvt.co2), float(gas_pvt.h2s), float(gas_pvt.n2),
399
+ float(gas_pvt.h2), float(getattr(gas_pvt, 'he', 0))],
400
+ float(gas_pvt.tc), float(gas_pvt.pc))
400
401
 
401
402
 
402
403
  def _prepare_flow_inputs(well_type, metric, gas_pvt=None, oil_pvt=None,
@@ -435,7 +436,7 @@ def _prepare_flow_inputs(well_type, metric, gas_pvt=None, oil_pvt=None,
435
436
  if gas_pvt is not None and well_type == 'gas':
436
437
  if f.gsg == 0.65:
437
438
  f.gsg = gas_pvt.sg
438
- f.tc, f.pc = _gas_pvt_tc_pc(gas_pvt)
439
+ f.zspec = _gas_pvt_zspec(gas_pvt)
439
440
 
440
441
  # OilPVT already holds oilfield units
441
442
  if oil_pvt is not None and well_type == 'oil':
@@ -1063,7 +1064,25 @@ def _condensate_vis(pr, cgr_local, gsg, api, temp_f, p_avg, oil_vis):
1063
1064
  return oil_vis
1064
1065
 
1065
1066
 
1066
- def _static_gas_column_pressure(thp, length, tht, bht, gsg, theta=math.pi / 2.0):
1067
+ def _march_gas_z_mu(gsg, temp_f, press_psia, tc, pc, zspec, viscosity=True):
1068
+ """(Z, gas viscosity cP) for the gas march.
1069
+
1070
+ zspec None: Hall-Yarborough on (tc, pc) and Lee-Gonzalez-Eakin. Otherwise
1071
+ the GasPVT methods carried by zspec (see _gas_pvt_zspec). viscosity=False
1072
+ returns (Z, None).
1073
+ """
1074
+ if zspec is None:
1075
+ zee = _z_factor(gsg, temp_f, press_psia, tc=tc, pc=pc)
1076
+ mu = _gas_viscosity(gsg, temp_f, press_psia, z=zee, tc=tc, pc=pc) if viscosity else None
1077
+ return zee, mu
1078
+ zmethod, cmethod, sg, (co2, h2s, n2, h2, he), tc_z, pc_z = zspec
1079
+ kw = dict(p=press_psia, sg=sg, degf=temp_f, zmethod=zmethod, cmethod=cmethod,
1080
+ co2=co2, h2s=h2s, n2=n2, h2=h2, he=he, tc=tc_z, pc=pc_z)
1081
+ zee = float(gas.gas_z(**kw))
1082
+ return zee, (float(gas.gas_ug(**kw)) if viscosity else None)
1083
+
1084
+
1085
+ def _static_gas_column_pressure(thp, length, tht, bht, gsg, theta=math.pi / 2.0, zspec=None):
1067
1086
  tc, pc = _sutton_tc_pc(gsg)
1068
1087
  n_seg = 50
1069
1088
  d_len = length / n_seg
@@ -1073,7 +1092,7 @@ def _static_gas_column_pressure(thp, length, tht, bht, gsg, theta=math.pi / 2.0)
1073
1092
  frac = (i + 0.5) / n_seg
1074
1093
  temp_local = tht + (bht - tht) * frac
1075
1094
  temp_r = temp_local + 459.67
1076
- zee = _z_factor(gsg, temp_local, max(p, 14.7), tc=tc, pc=pc)
1095
+ zee, _ = _march_gas_z_mu(gsg, temp_local, max(p, 14.7), tc, pc, zspec, viscosity=False)
1077
1096
  rho_gas = _MW_AIR * gsg * p / (zee * _R_GAS * temp_r)
1078
1097
  p += rho_gas / _IN2_PER_FT2 * d_len * sin_theta
1079
1098
  return p
@@ -1186,11 +1205,11 @@ def _hb_gradient_gas(s):
1186
1205
  def _hb_fbhp_gas(thp, api, gsg, tid, rough, length, tht, bht,
1187
1206
  wsg, qg_mmscfd, cgr, qw_bwpd, oil_vis,
1188
1207
  injection=False, pr=0.0, theta=math.pi / 2.0,
1189
- tc=None, pc=None):
1208
+ zspec=None):
1190
1209
  return _segment_march_gas(thp, api, gsg, tid, rough, length, tht, bht,
1191
1210
  wsg, qg_mmscfd, cgr, qw_bwpd, oil_vis,
1192
1211
  injection, pr, theta, _hb_gradient_gas,
1193
- tc=tc, pc=pc)
1212
+ zspec=zspec)
1194
1213
 
1195
1214
 
1196
1215
  @rust_accelerated('hb_fbhp_oil_rust')
@@ -1312,11 +1331,11 @@ def _wg_gradient_gas(s):
1312
1331
  def _wg_fbhp_gas(thp, api, gsg, tid, rough, length, tht, bht,
1313
1332
  wsg, qg_mmscfd, cgr, qw_bwpd, oil_vis,
1314
1333
  injection=False, pr=0.0, theta=math.pi / 2.0,
1315
- tc=None, pc=None):
1334
+ zspec=None):
1316
1335
  return _segment_march_gas(thp, api, gsg, tid, rough, length, tht, bht,
1317
1336
  wsg, qg_mmscfd, cgr, qw_bwpd, oil_vis,
1318
1337
  injection, pr, theta, _wg_gradient_gas,
1319
- tc=tc, pc=pc)
1338
+ zspec=zspec)
1320
1339
 
1321
1340
 
1322
1341
  @rust_accelerated('wg_fbhp_oil_rust')
@@ -1404,16 +1423,16 @@ def _gray_effective_roughness(rough_dry, sigma, rho_ns, v_sl, v_sg):
1404
1423
 
1405
1424
  def _segment_march_gas(thp, api, gsg, tid, rough, length, tht, bht,
1406
1425
  wsg, qg_mmscfd, cgr, qw_bwpd, oil_vis,
1407
- injection, pr, theta, gradient_fn, tc=None, pc=None):
1426
+ injection, pr, theta, gradient_fn, zspec=None):
1408
1427
  """Shared segment march for all gas VLP methods.
1409
1428
 
1410
1429
  gradient_fn(s) -> dpdz (psi/ft)
1411
1430
  Called at each pressure iteration with a dict containing all
1412
1431
  computed PVT/flow properties for the current segment step.
1413
- tc, pc: mixture pseudo-criticals (deg R, psia); None -> Sutton from gsg.
1432
+ zspec: GasPVT Z/viscosity spec (_gas_pvt_zspec); None -> Hall-Yarborough
1433
+ on Sutton pseudo-criticals of gsg with Lee-Gonzalez-Eakin viscosity.
1414
1434
  """
1415
- if tc is None or pc is None:
1416
- tc, pc = _sutton_tc_pc(gsg)
1435
+ tc, pc = _sutton_tc_pc(gsg)
1417
1436
  osg = 141.5 / (api + 131.5)
1418
1437
  total_mass = (_RHO_AIR_STC * gsg * qg_mmscfd * 1e6 +
1419
1438
  osg * _RHO_FW * cgr * qg_mmscfd * _FT3_PER_BBL +
@@ -1432,7 +1451,7 @@ def _segment_march_gas(thp, api, gsg, tid, rough, length, tht, bht,
1432
1451
  "the specified liquid rates (liquid loading not modelled).",
1433
1452
  RuntimeWarning, stacklevel=3
1434
1453
  )
1435
- return _static_gas_column_pressure(thp, length, tht, bht, gsg, theta=theta)
1454
+ return _static_gas_column_pressure(thp, length, tht, bht, gsg, theta=theta, zspec=zspec)
1436
1455
 
1437
1456
  diam_ft = tid / 12.0
1438
1457
  rough_ft = rough / 12.0
@@ -1466,8 +1485,7 @@ def _segment_march_gas(thp, api, gsg, tid, rough, length, tht, bht,
1466
1485
  oil_vis_loc = _condensate_vis(pr, cgr_loc, gsg, api,
1467
1486
  temp_f, p_avg, oil_vis)
1468
1487
 
1469
- zee = _z_factor(gsg, temp_f, p_avg, tc=tc, pc=pc)
1470
- mu_g = _gas_viscosity(gsg, temp_f, p_avg, z=zee, tc=tc, pc=pc)
1488
+ zee, mu_g = _march_gas_z_mu(gsg, temp_f, p_avg, tc, pc, zspec)
1471
1489
 
1472
1490
  rho_g = _MW_AIR * gsg * p_avg / (zee * _R_GAS * temp_r)
1473
1491
  rho_l = lsg_loc * _RHO_FW
@@ -1506,7 +1524,7 @@ def _segment_march_gas(thp, api, gsg, tid, rough, length, tht, bht,
1506
1524
  'qg_mmscfd': qg_mmscfd, 'api': api,
1507
1525
  }
1508
1526
 
1509
- dpdz = gradient_fn(s)
1527
+ dpdz = _low_liquid_gradient(gradient_fn, s)
1510
1528
  p_est = p_psia + dpdz * seg_len
1511
1529
 
1512
1530
  p_psia = p_est
@@ -1518,6 +1536,25 @@ def _segment_march_gas(thp, api, gsg, tid, rough, length, tht, bht,
1518
1536
  return p_psia
1519
1537
 
1520
1538
 
1539
+ def _low_liquid_gradient(gradient_fn, s):
1540
+ """Gradient with a continuous approach to the dry-gas limit.
1541
+
1542
+ For 0 < lambda_l < _LOW_LIQ_LAMBDA returns g0 + (lambda_l/_LOW_LIQ_LAMBDA)(g - g0),
1543
+ where g is the method's two-phase gradient and g0 the same method with the
1544
+ liquid removed (its existing lambda_l = 0 path). At lambda_l = 0 and at or
1545
+ above _LOW_LIQ_LAMBDA this is exactly gradient_fn(s).
1546
+ """
1547
+ g = gradient_fn(s)
1548
+ lam = s['lambda_l']
1549
+ if not 0.0 < lam < _LOW_LIQ_LAMBDA:
1550
+ return g
1551
+ s0 = dict(s, mflow_l=0.0, mflow_o=0.0, mflow_w=0.0, v_sl=0.0,
1552
+ v_m=s['v_sg'], lambda_l=0.0, rho_ns=s['rho_g'],
1553
+ mflow_total=s['mflow_g'], qo_loc=0.0, ql_loc=0.0, qw_bwpd=0.0)
1554
+ g0 = gradient_fn(s0)
1555
+ return g0 + (lam / _LOW_LIQ_LAMBDA) * (g - g0)
1556
+
1557
+
1521
1558
  # ============================================================================
1522
1559
  # Shared Oil Segment March
1523
1560
  # ============================================================================
@@ -1673,11 +1710,11 @@ def _gray_gradient_gas(s):
1673
1710
  def _gray_fbhp_gas(thp, api, gsg, tid, rough, length, tht, bht,
1674
1711
  wsg, qg_mmscfd, cgr, qw_bwpd, oil_vis,
1675
1712
  injection=False, pr=0.0, theta=math.pi / 2.0,
1676
- tc=None, pc=None):
1713
+ zspec=None):
1677
1714
  return _segment_march_gas(thp, api, gsg, tid, rough, length, tht, bht,
1678
1715
  wsg, qg_mmscfd, cgr, qw_bwpd, oil_vis,
1679
1716
  injection, pr, theta, _gray_gradient_gas,
1680
- tc=tc, pc=pc)
1717
+ zspec=zspec)
1681
1718
 
1682
1719
 
1683
1720
  @rust_accelerated('gray_fbhp_oil_rust')
@@ -1857,12 +1894,12 @@ def _bb_gradient_gas(s):
1857
1894
  def _bb_core_gas(thp, api, gsg, tid, rough, length, tht, bht,
1858
1895
  wsg, qg_mmscfd, cgr, qw_bwpd, oil_vis,
1859
1896
  injection=False, pr=0.0, theta=math.pi / 2.0,
1860
- tc=None, pc=None):
1897
+ zspec=None):
1861
1898
  """Beggs & Brill core for gas wells."""
1862
1899
  return _segment_march_gas(thp, api, gsg, tid, rough, length, tht, bht,
1863
1900
  wsg, qg_mmscfd, cgr, qw_bwpd, oil_vis,
1864
1901
  injection, pr, theta, _bb_gradient_gas,
1865
- tc=tc, pc=pc)
1902
+ zspec=zspec)
1866
1903
 
1867
1904
 
1868
1905
  @rust_accelerated('bb_fbhp_oil_rust')
@@ -1975,7 +2012,7 @@ def fbhp(thp: float, completion: 'Completion', vlpmethod: str = 'WG', well_type:
1975
2012
  length=length, tht=tht_seg, bht=bht_seg, wsg=wsg,
1976
2013
  qg_mmscfd=f.qg_mmscfd, cgr=f.cgr, qw_bwpd=f.qw_bwpd,
1977
2014
  oil_vis=oil_vis, injection=injection, pr=f.pr, theta=theta,
1978
- tc=f.tc, pc=f.pc)
2015
+ zspec=f.zspec)
1979
2016
  else:
1980
2017
  return _OIL_METHOD_DIC[vlpmethod.name](
1981
2018
  thp=thp_in, api=f.api, gsg=f.gsg, tid=tid, rough=rough,
@@ -30,8 +30,6 @@ from typing import Union, Tuple
30
30
  import numpy as np
31
31
  import numpy.typing as npt
32
32
  from tabulate import tabulate
33
- from ilt import gwr
34
- from mpmath import mp
35
33
 
36
34
  from pyrestoolbox._accelerator import RUST_AVAILABLE, _rust_module
37
35
 
@@ -74,7 +72,17 @@ def influence_tables(
74
72
  if RUST_AVAILABLE:
75
73
  pDs = _rust_module.influence_tables_rust(tD.tolist(), list(ReDs), M)
76
74
  else:
77
- # Python fallback via ilt library
75
+ # Python fallback via ilt library (optional extra: pyrestoolbox[aquifer])
76
+ try:
77
+ from ilt import gwr
78
+ from mpmath import mp
79
+ except ImportError as e:
80
+ raise ImportError(
81
+ "influence_tables needs the Rust extension or the optional "
82
+ "inverse-Laplace dependencies; install them with "
83
+ "pip install 'pyrestoolbox[aquifer]'"
84
+ ) from e
85
+
78
86
  def laplace_Ps(s: float, ReD: float):
79
87
  x = mp.sqrt(s)
80
88
  # pre-calculate duplicated bessel function for greater efficiency
@@ -17,10 +17,13 @@ install_requires =
17
17
  scipy
18
18
  pandas
19
19
  tabulate
20
+ openpyxl
21
+
22
+ [options.extras_require]
23
+ aquifer =
20
24
  ilt-inversion
21
25
  mpmath
22
26
  gmpy2
23
- openpyxl
24
27
 
25
28
  [options.packages.find]
26
29
  exclude =
@@ -32,9 +32,9 @@ setup(
32
32
  'scipy',
33
33
  'pandas',
34
34
  'tabulate',
35
- 'ilt-inversion',
36
- 'mpmath',
37
- 'gmpy2',
38
35
  'openpyxl'
39
- ]
36
+ ],
37
+ extras_require={
38
+ 'aquifer': ['ilt-inversion', 'mpmath', 'gmpy2'],
39
+ }
40
40
  )