pyrestoolbox 3.8.5__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.5 → pyrestoolbox-3.8.6}/Cargo.lock +1 -1
  2. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/Cargo.toml +1 -1
  3. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/PKG-INFO +6 -5
  4. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/README.rst +1 -1
  5. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyproject.toml +5 -4
  6. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/changelist.rst +6 -0
  7. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/simtools.rst +2 -0
  8. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/simtools/_aquifer.py +11 -3
  9. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/setup.cfg +4 -1
  10. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/setup.py +4 -4
  11. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/gwr.rs +83 -59
  12. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/.github/complexity-baseline.json +0 -0
  13. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/.github/scripts/check_complexity.py +0 -0
  14. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/.github/workflows/build-wheels.yml +0 -0
  15. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/.github/workflows/tests.yml +0 -0
  16. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/.gitignore +0 -0
  17. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/LICENSE +0 -0
  18. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/MANIFEST.in +0 -0
  19. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/ResToolbox/privacy_policy.md +0 -0
  20. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/build_pure_python.py +0 -0
  21. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/clippy.toml +0 -0
  22. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/mcp/Dockerfile +0 -0
  23. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/mcp/README.md +0 -0
  24. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/mcp/pyproject.toml +0 -0
  25. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/mcp/pyrestoolbox_mcp/__init__.py +0 -0
  26. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/mcp/pyrestoolbox_mcp/serialize.py +0 -0
  27. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/mcp/pyrestoolbox_mcp/server.py +0 -0
  28. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/mcp/tests/test_server.py +0 -0
  29. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/__init__.py +0 -0
  30. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/_accelerator.py +0 -0
  31. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/__init__.py +0 -0
  32. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/_lib_dielectric.py +0 -0
  33. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/_lib_maoduan_viscosity.py +0 -0
  34. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/_lib_pitzer_params.py +0 -0
  35. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/_lib_salting_library.py +0 -0
  36. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/_lib_vle_engine.py +0 -0
  37. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/appelo_volumes.py +0 -0
  38. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/brine.py +0 -0
  39. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/iapws_viscosity.py +0 -0
  40. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/jones_dole_viscosity.py +0 -0
  41. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/kestin_nacl_viscosity.py +0 -0
  42. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/pr_vphi.py +0 -0
  43. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/viscosity_route.py +0 -0
  44. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/brine/vphi_route.py +0 -0
  45. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/classes/__init__.py +0 -0
  46. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/classes/classes.py +0 -0
  47. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/constants/__init__.py +0 -0
  48. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/constants/constants.py +0 -0
  49. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/dca/__init__.py +0 -0
  50. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/dca/dca.py +0 -0
  51. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/brine.rst +0 -0
  52. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/dca.rst +0 -0
  53. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/examples.ipynb +0 -0
  54. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/gas.rst +0 -0
  55. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/img/bot.png +0 -0
  56. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/img/bot_PVTO.png +0 -0
  57. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/img/bot_img.png +0 -0
  58. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/img/dry_gas.png +0 -0
  59. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/img/grid_sat_df.png +0 -0
  60. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/img/influence.png +0 -0
  61. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/img/properties_df.png +0 -0
  62. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/img/sgof.png +0 -0
  63. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/img/swof.png +0 -0
  64. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/index.rst +0 -0
  65. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/layer.rst +0 -0
  66. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/library.rst +0 -0
  67. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/matbal.rst +0 -0
  68. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/nodal.rst +0 -0
  69. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/nodal_examples.ipynb +0 -0
  70. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/nodal_hydrate_demo.ipynb +0 -0
  71. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/oil.rst +0 -0
  72. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/plyasunov.rst +0 -0
  73. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/recommend.rst +0 -0
  74. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/docs/sensitivity.rst +0 -0
  75. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/gas/__init__.py +0 -0
  76. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/gas/_hydrate.py +0 -0
  77. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/gas/gas.py +0 -0
  78. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/layer/__init__.py +0 -0
  79. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/layer/layer.py +0 -0
  80. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/library/__init__.py +0 -0
  81. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/library/component_library.xlsx +0 -0
  82. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/library/library.py +0 -0
  83. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/matbal/__init__.py +0 -0
  84. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/matbal/matbal.py +0 -0
  85. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/nodal/__init__.py +0 -0
  86. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/nodal/nodal.py +0 -0
  87. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/__init__.py +0 -0
  88. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_compressibility.py +0 -0
  89. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_constants.py +0 -0
  90. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_correlations.py +0 -0
  91. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_density.py +0 -0
  92. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_harmonize.py +0 -0
  93. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_pvt_class.py +0 -0
  94. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_rate.py +0 -0
  95. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_separator.py +0 -0
  96. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_tables.py +0 -0
  97. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/oil/_utils.py +0 -0
  98. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/plyasunov/__init__.py +0 -0
  99. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/plyasunov/iapws_if97.py +0 -0
  100. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/plyasunov/plyasunov_model.py +0 -0
  101. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/plyasunov/water_properties.py +0 -0
  102. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/recommend/__init__.py +0 -0
  103. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/recommend/recommend.py +0 -0
  104. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/sensitivity/__init__.py +0 -0
  105. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/sensitivity/sensitivity.py +0 -0
  106. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/shared_fns/__init__.py +0 -0
  107. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/shared_fns/shared_fns.py +0 -0
  108. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/simtools/__init__.py +0 -0
  109. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/simtools/_decks.py +0 -0
  110. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/simtools/_pvt_tables.py +0 -0
  111. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/simtools/_relperm.py +0 -0
  112. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/simtools/_vfp.py +0 -0
  113. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/simtools/simtools.py +0 -0
  114. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/validate/__init__.py +0 -0
  115. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/pyrestoolbox/validate/validate.py +0 -0
  116. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/bessel.rs +0 -0
  117. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/brine_visc/mod.rs +0 -0
  118. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/brine_visc/salt.rs +0 -0
  119. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/brine_visc/water.rs +0 -0
  120. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/critical_properties/mod.rs +0 -0
  121. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/dca/hyperbolic.rs +0 -0
  122. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/dca/mod.rs +0 -0
  123. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/dca/ransac.rs +0 -0
  124. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/gas_viscosity/mod.rs +0 -0
  125. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/lib.rs +0 -0
  126. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/matbal/mod.rs +0 -0
  127. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/matbal/objective.rs +0 -0
  128. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/oil/density.rs +0 -0
  129. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/oil/mod.rs +0 -0
  130. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/pseudopressure.rs +0 -0
  131. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/spycher_pruess/mod.rs +0 -0
  132. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/spycher_pruess/solubility.rs +0 -0
  133. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/vle/alpha.rs +0 -0
  134. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/vle/bip.rs +0 -0
  135. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/vle/components.rs +0 -0
  136. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/vle/eos.rs +0 -0
  137. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/vle/flash.rs +0 -0
  138. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/vle/fugacity.rs +0 -0
  139. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/vle/k_init.rs +0 -0
  140. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/vle/mod.rs +0 -0
  141. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/vle/rachford_rice.rs +0 -0
  142. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/vlp/constants.rs +0 -0
  143. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/vlp/friction.rs +0 -0
  144. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/vlp/holdup_bb.rs +0 -0
  145. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/vlp/holdup_gray.rs +0 -0
  146. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/vlp/holdup_wg.rs +0 -0
  147. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/vlp/ift.rs +0 -0
  148. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/vlp/march.rs +0 -0
  149. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/vlp/mod.rs +0 -0
  150. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/vlp/pvt_helpers.rs +0 -0
  151. {pyrestoolbox-3.8.5 → pyrestoolbox-3.8.6}/src/vlp/static_column.rs +0 -0
  152. {pyrestoolbox-3.8.5 → 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.5"
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.5"
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.5
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.5"
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,9 @@
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
+
1
7
  Changelist in 3.8.5:
2
8
 
3
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).
@@ -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
@@ -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
  )
@@ -13,7 +13,7 @@
13
13
 
14
14
  use pyo3::prelude::*;
15
15
  use rug::Float;
16
- use rug::float::Round;
16
+ use rug::float::{Constant, Round};
17
17
  use rug::ops::AssignRound;
18
18
 
19
19
  // =========================================================================
@@ -46,10 +46,39 @@ fn float_from_f64(val: f64, prec: u32) -> Float {
46
46
  // Small x: power series for I_n(x), then multiply by exp(-x) / exp(x).
47
47
  // Large x: asymptotic expansion gives scaled forms directly.
48
48
  //
49
- // Threshold: x > 20 uses asymptotic. Series converges for all x but
50
- // K_n series has catastrophic cancellation for large x.
49
+ // The switch point depends on the working precision. The asymptotic series,
50
+ // optimally truncated, is only good to a relative e^(-2x), so it is used only
51
+ // once that is below 2^-prec (with a margin). Below the switch the K_n series
52
+ // cancels terms of size e^x down to a result of size e^-x, so the series runs
53
+ // with 2x*log2(e) guard bits. A fixed x > 25 switch with x*log2(e) guard bits
54
+ // limited the transform to about 22 digits; GWR needs about 2.1*M digits.
55
+
56
+ const ASYMP_MARGIN_BITS: f64 = 16.0;
57
+ const SERIES_EXTRA_GUARD_BITS: u32 = 20;
58
+
59
+ /// True when the asymptotic expansion reaches `prec` bits at `x`.
60
+ fn use_asymptotic(x: &Float, prec: u32) -> bool {
61
+ 2.0 * x.to_f64() * std::f64::consts::LOG2_E > prec as f64 + ASYMP_MARGIN_BITS
62
+ }
63
+
64
+ /// True when `term` no longer changes `sum` at `prec` bits.
65
+ fn series_negligible(term: &Float, sum: &Float, prec: u32) -> bool {
66
+ match (term.get_exp(), sum.get_exp()) {
67
+ (Some(te), Some(se)) => te < se - prec as i32,
68
+ _ => term.is_zero(),
69
+ }
70
+ }
51
71
 
52
- const BESSEL_THRESHOLD: f64 = 25.0;
72
+ /// Scaled Bessel value from a power series: series(x) * exp(exp_sign * x),
73
+ /// evaluated with enough guard bits to absorb the K_n cancellation.
74
+ fn scaled_series(x: &Float, prec: u32, series: fn(&Float, u32) -> Float, exp_sign: i32) -> Float {
75
+ let guard = (2.0 * x.to_f64() * std::f64::consts::LOG2_E).ceil() as u32 + SERIES_EXTRA_GUARD_BITS;
76
+ let hp = prec + guard;
77
+ let xhp = Float::with_val(hp, x);
78
+ let val = series(&xhp, hp);
79
+ let scale = Float::with_val(hp, &xhp * exp_sign).exp();
80
+ Float::with_val(prec, Float::with_val(hp, &val * &scale))
81
+ }
53
82
 
54
83
  // --- Asymptotic expansion for large x ---
55
84
  // I_ν(x) ~ e^x / sqrt(2πx) * sum_{k=0}^K (-1)^k * a_k(ν) / x^k
@@ -98,7 +127,7 @@ fn mpfr_besseli0e_asymp(x: &Float, prec: u32) -> Float {
98
127
  }
99
128
 
100
129
  // I_0e(x) = sum / sqrt(2*pi*x)
101
- let two_pi_x = Float::with_val(prec, x * std::f64::consts::TAU);
130
+ let two_pi_x = Float::with_val(prec, x * Float::with_val(prec, Constant::Pi)) * 2u32;
102
131
  Float::with_val(prec, &sum / two_pi_x.sqrt())
103
132
  }
104
133
 
@@ -112,8 +141,10 @@ fn mpfr_besseli1e_asymp(x: &Float, prec: u32) -> Float {
112
141
 
113
142
  for k in 1u64..200 {
114
143
  let sq = (2 * k - 1) * (2 * k - 1);
115
- // factor for nu=1: (4 - (2k-1)^2) / (8*k*x)
116
- let numer = 4i64 - sq as i64;
144
+ // factor for nu=1: -(4 - (2k-1)^2) / (8*k*x), the minus being the (-1)^k
145
+ // of the I expansion (I_0 folds it in the same way, as +(2k-1)^2):
146
+ // 1 - 3/(8x) - 15/(128x^2) - ..., A&S 9.7.1
147
+ let numer = sq as i64 - 4i64;
117
148
  a_k *= Float::with_val(prec, numer);
118
149
  a_k /= 8u32 * k as u32;
119
150
  a_k *= &one_over_x;
@@ -126,7 +157,7 @@ fn mpfr_besseli1e_asymp(x: &Float, prec: u32) -> Float {
126
157
  sum += &a_k;
127
158
  }
128
159
 
129
- let two_pi_x = Float::with_val(prec, x * std::f64::consts::TAU);
160
+ let two_pi_x = Float::with_val(prec, x * Float::with_val(prec, Constant::Pi)) * 2u32;
130
161
  Float::with_val(prec, &sum / two_pi_x.sqrt())
131
162
  }
132
163
 
@@ -181,7 +212,7 @@ fn mpfr_besselk0e_asymp(x: &Float, prec: u32) -> Float {
181
212
  sum += &a_k;
182
213
  }
183
214
 
184
- let pi_over_2x = Float::with_val(prec, std::f64::consts::FRAC_PI_2) / x;
215
+ let pi_over_2x = Float::with_val(prec, Float::with_val(prec, Constant::Pi) / x) / 2u32;
185
216
  Float::with_val(prec, &sum * pi_over_2x.sqrt())
186
217
  }
187
218
 
@@ -208,7 +239,7 @@ fn mpfr_besselk1e_asymp(x: &Float, prec: u32) -> Float {
208
239
  sum += &a_k;
209
240
  }
210
241
 
211
- let pi_over_2x = Float::with_val(prec, std::f64::consts::FRAC_PI_2) / x;
242
+ let pi_over_2x = Float::with_val(prec, Float::with_val(prec, Constant::Pi) / x) / 2u32;
212
243
  Float::with_val(prec, &sum * pi_over_2x.sqrt())
213
244
  }
214
245
 
@@ -224,7 +255,7 @@ fn mpfr_besseli0_series(x: &Float, prec: u32) -> Float {
224
255
  term *= &x2_over4;
225
256
  term /= k * k;
226
257
  result += &term;
227
- if term.is_zero() || (k > 10 && Float::with_val(prec, &term / &result).to_f64().abs() < 1e-50) {
258
+ if k > 10 && series_negligible(&term, &result, prec) {
228
259
  break;
229
260
  }
230
261
  }
@@ -241,7 +272,7 @@ fn mpfr_besseli1_series(x: &Float, prec: u32) -> Float {
241
272
  term *= &x2_over4;
242
273
  term /= k * (k + 1);
243
274
  sum += &term;
244
- if term.is_zero() || (k > 10 && Float::with_val(prec, &term / &sum).to_f64().abs() < 1e-50) {
275
+ if k > 10 && series_negligible(&term, &sum, prec) {
245
276
  break;
246
277
  }
247
278
  }
@@ -252,8 +283,7 @@ fn mpfr_besseli1_series(x: &Float, prec: u32) -> Float {
252
283
  /// K_0(x) = -(ln(x/2) + gamma) * I_0(x) + sum_{k=1}^inf H_k * (x^2/4)^k / (k!)^2
253
284
  fn mpfr_besselk0_series(x: &Float, prec: u32) -> Float {
254
285
  let i0 = mpfr_besseli0_series(x, prec);
255
- let gamma = Float::with_val(prec,
256
- Float::parse("0.57721566490153286060651209008240243104215933593992").unwrap());
286
+ let gamma = Float::with_val(prec, Constant::Euler);
257
287
  let ln_x_over_2 = Float::with_val(prec, x / 2u32).ln();
258
288
 
259
289
  let mut result = Float::with_val(prec, &ln_x_over_2 + &gamma);
@@ -270,7 +300,7 @@ fn mpfr_besselk0_series(x: &Float, prec: u32) -> Float {
270
300
  h_k += Float::with_val(prec, 1) / Float::with_val(prec, k);
271
301
  let contribution = Float::with_val(prec, &h_k * &term);
272
302
  result += &contribution;
273
- if contribution.is_zero() || (k > 10 && Float::with_val(prec, &contribution / &result).to_f64().abs() < 1e-50) {
303
+ if k > 10 && series_negligible(&contribution, &result, prec) {
274
304
  break;
275
305
  }
276
306
  }
@@ -289,59 +319,19 @@ fn mpfr_besselk1_series(x: &Float, prec: u32) -> Float {
289
319
  // --- Dispatch: series or asymptotic ---
290
320
 
291
321
  fn mpfr_besseli0e(x: &Float, prec: u32) -> Float {
292
- if x.to_f64() < BESSEL_THRESHOLD {
293
- // I_0(x)*exp(-x): I_0 ~ exp(x)/sqrt(2πx), so product ~ 1/sqrt(2πx).
294
- // Need guard bits ≈ x*log2(e) to preserve precision in I_0 before scaling.
295
- let guard = (x.to_f64() * std::f64::consts::LOG2_E).ceil() as u32 + 20;
296
- let hp = prec + guard;
297
- let xhp = Float::with_val(hp, x);
298
- let i0 = mpfr_besseli0_series(&xhp, hp);
299
- let result = Float::with_val(hp, &i0 * Float::with_val(hp, -&xhp).exp());
300
- Float::with_val(prec, &result)
301
- } else {
302
- mpfr_besseli0e_asymp(x, prec)
303
- }
322
+ if use_asymptotic(x, prec) { mpfr_besseli0e_asymp(x, prec) } else { scaled_series(x, prec, mpfr_besseli0_series, -1) }
304
323
  }
305
324
 
306
325
  fn mpfr_besseli1e(x: &Float, prec: u32) -> Float {
307
- if x.to_f64() < BESSEL_THRESHOLD {
308
- let guard = (x.to_f64() * std::f64::consts::LOG2_E).ceil() as u32 + 20;
309
- let hp = prec + guard;
310
- let xhp = Float::with_val(hp, x);
311
- let i1 = mpfr_besseli1_series(&xhp, hp);
312
- let result = Float::with_val(hp, &i1 * Float::with_val(hp, -&xhp).exp());
313
- Float::with_val(prec, &result)
314
- } else {
315
- mpfr_besseli1e_asymp(x, prec)
316
- }
326
+ if use_asymptotic(x, prec) { mpfr_besseli1e_asymp(x, prec) } else { scaled_series(x, prec, mpfr_besseli1_series, -1) }
317
327
  }
318
328
 
319
329
  fn mpfr_besselk0e(x: &Float, prec: u32) -> Float {
320
- if x.to_f64() < BESSEL_THRESHOLD {
321
- // Guard bits to compensate for cancellation in K_0 series.
322
- // Cancellation is O(e^x), needing ~x*log2(e) extra bits.
323
- let guard = (x.to_f64() * std::f64::consts::LOG2_E).ceil() as u32 + 20;
324
- let hp = prec + guard;
325
- let xhp = Float::with_val(hp, x);
326
- let k0 = mpfr_besselk0_series(&xhp, hp);
327
- let result = Float::with_val(hp, &k0 * xhp.exp());
328
- Float::with_val(prec, &result)
329
- } else {
330
- mpfr_besselk0e_asymp(x, prec)
331
- }
330
+ if use_asymptotic(x, prec) { mpfr_besselk0e_asymp(x, prec) } else { scaled_series(x, prec, mpfr_besselk0_series, 1) }
332
331
  }
333
332
 
334
333
  fn mpfr_besselk1e(x: &Float, prec: u32) -> Float {
335
- if x.to_f64() < BESSEL_THRESHOLD {
336
- let guard = (x.to_f64() * std::f64::consts::LOG2_E).ceil() as u32 + 20;
337
- let hp = prec + guard;
338
- let xhp = Float::with_val(hp, x);
339
- let k1 = mpfr_besselk1_series(&xhp, hp);
340
- let result = Float::with_val(hp, &k1 * xhp.exp());
341
- Float::with_val(prec, &result)
342
- } else {
343
- mpfr_besselk1e_asymp(x, prec)
344
- }
334
+ if use_asymptotic(x, prec) { mpfr_besselk1e_asymp(x, prec) } else { scaled_series(x, prec, mpfr_besselk1_series, 1) }
345
335
  }
346
336
 
347
337
  // =========================================================================
@@ -620,6 +610,40 @@ mod tests {
620
610
  assert!(k0e.to_f64() > 0.0);
621
611
  }
622
612
 
613
+ /// Series and asymptotic paths agree to the working precision just past
614
+ /// the switch point, at the precisions GWR uses for M = 12 and M = 32.
615
+ #[test]
616
+ fn test_bessel_series_asymptotic_overlap() {
617
+ type Pair = (fn(&Float, u32) -> Float, fn(&Float, u32) -> Float, i32);
618
+ let pairs: [Pair; 4] = [
619
+ (mpfr_besseli0_series, mpfr_besseli0e_asymp, -1),
620
+ (mpfr_besseli1_series, mpfr_besseli1e_asymp, -1),
621
+ (mpfr_besselk0_series, mpfr_besselk0e_asymp, 1),
622
+ (mpfr_besselk1_series, mpfr_besselk1e_asymp, 1),
623
+ ];
624
+ for prec in [dec_to_bits(25), dec_to_bits(67)] {
625
+ let x_switch = (prec as f64 + ASYMP_MARGIN_BITS) / (2.0 * std::f64::consts::LOG2_E);
626
+ let x = Float::with_val(prec, x_switch + 0.5);
627
+ for (series, asymp, sign) in pairs {
628
+ let a = scaled_series(&x, prec, series, sign);
629
+ let b = asymp(&x, prec);
630
+ let rel = Float::with_val(prec, Float::with_val(prec, &a - &b) / &b).abs();
631
+ let bits = -rel.to_f64().log2();
632
+ assert!(bits > prec as f64 - 12.0, "prec {}: only {:.0} bits agree", prec, bits);
633
+ }
634
+ }
635
+ }
636
+
637
+ /// K_0 at the GWR abscissa where a 60-bit evaluation loses every digit
638
+ /// (mpmath: K_0(23.548200450309494) = 1.52394442662604e-11).
639
+ #[test]
640
+ fn test_besselk0_mid_argument() {
641
+ let prec = dec_to_bits(15);
642
+ let x = Float::with_val(prec, 23.548200450309494);
643
+ let k0 = mpfr_besselk0e(&x, prec).to_f64() * (-23.548200450309494_f64).exp();
644
+ assert!((k0 / 1.52394442662604e-11 - 1.0).abs() < 1e-13, "K_0 = {}", k0);
645
+ }
646
+
623
647
  #[test]
624
648
  fn test_gwr_coefficients_m4() {
625
649
  let coeffs = GwrCoefficients::new(4, 20);
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes