pyrestoolbox 3.7.7__tar.gz → 3.8.3__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 (153) hide show
  1. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/.github/complexity-baseline.json +5 -8
  2. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/.github/workflows/build-wheels.yml +4 -4
  3. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/.github/workflows/tests.yml +30 -1
  4. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/.gitignore +3 -0
  5. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/Cargo.lock +1 -1
  6. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/Cargo.toml +1 -1
  7. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/PKG-INFO +18 -21
  8. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/README.rst +16 -18
  9. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/mcp/Dockerfile +1 -1
  10. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/mcp/README.md +12 -5
  11. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/mcp/pyproject.toml +2 -2
  12. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/mcp/pyrestoolbox_mcp/server.py +111 -17
  13. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/mcp/tests/test_server.py +92 -12
  14. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyproject.toml +2 -3
  15. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/__init__.py +0 -2
  16. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/_accelerator.py +20 -0
  17. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/brine/_lib_salting_library.py +1 -1
  18. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/brine/_lib_vle_engine.py +248 -102
  19. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/brine/brine.py +177 -67
  20. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/brine/pr_vphi.py +12 -4
  21. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/brine/vphi_route.py +2 -1
  22. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/constants/constants.py +3 -2
  23. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/dca/dca.py +36 -22
  24. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/brine.rst +74 -28
  25. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/changelist.rst +85 -0
  26. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/dca.rst +1 -1
  27. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/gas.rst +206 -59
  28. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/layer.rst +2 -2
  29. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/matbal.rst +4 -1
  30. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/nodal.rst +53 -50
  31. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/nodal_examples.ipynb +17 -19
  32. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/nodal_hydrate_demo.ipynb +23 -26
  33. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/oil.rst +7 -7
  34. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/recommend.rst +10 -4
  35. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/sensitivity.rst +1 -1
  36. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/simtools.rst +7 -1
  37. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/gas/_hydrate.py +55 -33
  38. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/gas/gas.py +231 -161
  39. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/layer/layer.py +1 -2
  40. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/matbal/matbal.py +8 -4
  41. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/nodal/nodal.py +309 -155
  42. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/oil/_compressibility.py +9 -16
  43. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/oil/_constants.py +12 -1
  44. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/oil/_correlations.py +39 -20
  45. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/oil/_density.py +2 -1
  46. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/oil/_harmonize.py +15 -29
  47. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/oil/_rate.py +2 -2
  48. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/oil/_tables.py +7 -6
  49. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/oil/_utils.py +17 -1
  50. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/plyasunov/plyasunov_model.py +13 -8
  51. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/recommend/recommend.py +11 -6
  52. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/shared_fns/shared_fns.py +66 -36
  53. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/simtools/_decks.py +16 -13
  54. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/simtools/_relperm.py +8 -1
  55. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/simtools/_vfp.py +41 -15
  56. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/setup.cfg +0 -1
  57. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/setup.py +0 -1
  58. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/bessel.rs +5 -0
  59. pyrestoolbox-3.8.3/src/brine_visc/mod.rs +61 -0
  60. pyrestoolbox-3.8.3/src/brine_visc/salt.rs +149 -0
  61. pyrestoolbox-3.8.3/src/brine_visc/water.rs +157 -0
  62. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/critical_properties/mod.rs +8 -4
  63. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/gas_viscosity/mod.rs +35 -26
  64. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/lib.rs +5 -0
  65. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/oil/density.rs +25 -17
  66. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/oil/mod.rs +1 -1
  67. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/pseudopressure.rs +14 -14
  68. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/spycher_pruess/solubility.rs +70 -37
  69. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/vle/bip.rs +23 -0
  70. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/vle/components.rs +9 -4
  71. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/vle/flash.rs +178 -9
  72. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/vle/k_init.rs +13 -1
  73. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/vlp/constants.rs +5 -1
  74. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/vlp/holdup_bb.rs +8 -3
  75. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/vlp/holdup_gray.rs +2 -2
  76. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/vlp/march.rs +48 -43
  77. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/vlp/mod.rs +19 -4
  78. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/vlp/pvt_helpers.rs +57 -13
  79. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/vlp/static_column.rs +2 -1
  80. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/zfactor/mod.rs +83 -53
  81. pyrestoolbox-3.7.7/mcp/DEPLOYMENT.md +0 -53
  82. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/.github/scripts/check_complexity.py +0 -0
  83. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/LICENSE +0 -0
  84. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/MANIFEST.in +0 -0
  85. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/ResToolbox/privacy_policy.md +0 -0
  86. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/build_pure_python.py +0 -0
  87. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/clippy.toml +0 -0
  88. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/mcp/pyrestoolbox_mcp/__init__.py +0 -0
  89. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/mcp/pyrestoolbox_mcp/serialize.py +0 -0
  90. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/brine/__init__.py +0 -0
  91. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/brine/_lib_dielectric.py +0 -0
  92. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/brine/_lib_maoduan_viscosity.py +0 -0
  93. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/brine/_lib_pitzer_params.py +0 -0
  94. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/brine/appelo_volumes.py +0 -0
  95. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/brine/iapws_viscosity.py +0 -0
  96. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/brine/jones_dole_viscosity.py +0 -0
  97. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/brine/kestin_nacl_viscosity.py +0 -0
  98. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/brine/viscosity_route.py +0 -0
  99. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/classes/__init__.py +0 -0
  100. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/classes/classes.py +0 -0
  101. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/constants/__init__.py +0 -0
  102. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/dca/__init__.py +0 -0
  103. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/examples.ipynb +0 -0
  104. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/img/bot.png +0 -0
  105. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/img/bot_PVTO.png +0 -0
  106. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/img/bot_img.png +0 -0
  107. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/img/dry_gas.png +0 -0
  108. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/img/grid_sat_df.png +0 -0
  109. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/img/influence.png +0 -0
  110. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/img/properties_df.png +0 -0
  111. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/img/sgof.png +0 -0
  112. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/img/swof.png +0 -0
  113. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/index.rst +0 -0
  114. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/library.rst +0 -0
  115. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/docs/plyasunov.rst +0 -0
  116. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/gas/__init__.py +0 -0
  117. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/layer/__init__.py +0 -0
  118. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/library/__init__.py +0 -0
  119. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/library/component_library.xlsx +0 -0
  120. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/library/library.py +0 -0
  121. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/matbal/__init__.py +0 -0
  122. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/nodal/__init__.py +0 -0
  123. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/oil/__init__.py +0 -0
  124. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/oil/_pvt_class.py +0 -0
  125. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/oil/_separator.py +0 -0
  126. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/plyasunov/__init__.py +0 -0
  127. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/plyasunov/iapws_if97.py +0 -0
  128. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/plyasunov/water_properties.py +0 -0
  129. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/recommend/__init__.py +0 -0
  130. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/sensitivity/__init__.py +0 -0
  131. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/sensitivity/sensitivity.py +0 -0
  132. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/shared_fns/__init__.py +0 -0
  133. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/simtools/__init__.py +0 -0
  134. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/simtools/_aquifer.py +0 -0
  135. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/simtools/_pvt_tables.py +0 -0
  136. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/simtools/simtools.py +0 -0
  137. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/validate/__init__.py +0 -0
  138. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/pyrestoolbox/validate/validate.py +0 -0
  139. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/dca/hyperbolic.rs +0 -0
  140. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/dca/mod.rs +0 -0
  141. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/dca/ransac.rs +0 -0
  142. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/gwr.rs +0 -0
  143. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/matbal/mod.rs +0 -0
  144. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/matbal/objective.rs +0 -0
  145. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/spycher_pruess/mod.rs +0 -0
  146. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/vle/alpha.rs +0 -0
  147. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/vle/eos.rs +0 -0
  148. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/vle/fugacity.rs +0 -0
  149. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/vle/mod.rs +0 -0
  150. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/vle/rachford_rice.rs +0 -0
  151. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/vlp/friction.rs +0 -0
  152. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/vlp/holdup_wg.rs +0 -0
  153. {pyrestoolbox-3.7.7 → pyrestoolbox-3.8.3}/src/vlp/ift.rs +0 -0
@@ -2,17 +2,15 @@
2
2
  "pyrestoolbox/brine/_lib_vle_engine.py::SWBinaryVLE.calc_gas_solubility": 16,
3
3
  "pyrestoolbox/brine/_lib_vle_engine.py::SWMultiComponentFlash.build_kij_matrix": 18,
4
4
  "pyrestoolbox/brine/_lib_vle_engine.py::SWMultiComponentFlash.calc_equilibrium": 24,
5
- "pyrestoolbox/brine/_lib_vle_engine.py::calc_gas_brine_equilibrium": 29,
5
+ "pyrestoolbox/brine/_lib_vle_engine.py::calc_gas_brine_equilibrium": 23,
6
6
  "pyrestoolbox/brine/brine.py::CO2_Brine_Mixture.__init__": 18,
7
- "pyrestoolbox/brine/brine.py::SoreideWhitson.__init__": 28,
7
+ "pyrestoolbox/brine/brine.py::SoreideWhitson.__init__": 27,
8
8
  "pyrestoolbox/brine/brine.py::SoreideWhitson._calc_properties": 19,
9
- "pyrestoolbox/brine/brine.py::brine_props": 19,
10
- "pyrestoolbox/dca/dca.py::fit_decline": 17,
11
- "pyrestoolbox/dca/dca.py::fit_decline_cum": 22,
9
+ "pyrestoolbox/brine/brine.py::brine_props": 17,
10
+ "pyrestoolbox/dca/dca.py::fit_decline_cum": 20,
12
11
  "pyrestoolbox/dca/dca.py::forecast": 16,
13
12
  "pyrestoolbox/dca/dca.py::hyp2_from_eur": 18,
14
13
  "pyrestoolbox/gas/_hydrate.py::gas_hydrate": 26,
15
- "pyrestoolbox/gas/gas.py::gas_ponz2p": 16,
16
14
  "pyrestoolbox/gas/gas.py::gas_tc_pc": 16,
17
15
  "pyrestoolbox/gas/gas.py::gas_ug": 16,
18
16
  "pyrestoolbox/matbal/matbal.py::gas_matbal": 26,
@@ -20,11 +18,10 @@
20
18
  "pyrestoolbox/nodal/nodal.py::Completion.__init__": 21,
21
19
  "pyrestoolbox/nodal/nodal.py::_bb_flow_pattern": 18,
22
20
  "pyrestoolbox/nodal/nodal.py::_prepare_flow_inputs": 16,
23
- "pyrestoolbox/nodal/nodal.py::ipr_curve": 27,
21
+ "pyrestoolbox/nodal/nodal.py::ipr_curve": 22,
24
22
  "pyrestoolbox/nodal/nodal.py::operating_point": 18,
25
23
  "pyrestoolbox/oil/_compressibility.py::oil_co": 16,
26
24
  "pyrestoolbox/oil/_correlations.py::oil_pbub": 16,
27
- "pyrestoolbox/oil/_harmonize.py::oil_harmonize": 16,
28
25
  "pyrestoolbox/shared_fns/shared_fns.py::validate_pe_inputs": 43,
29
26
  "pyrestoolbox/simtools/_decks.py::_crawl_deck_includes": 16,
30
27
  "pyrestoolbox/simtools/_decks.py::ix_extract_problem_cells": 41,
@@ -45,7 +45,7 @@ jobs:
45
45
  # Use maturin as the build frontend
46
46
  CIBW_BUILD_FRONTEND: "build"
47
47
  # Build for CPython 3.8-3.13 (last 5+ years of Python releases)
48
- CIBW_BUILD: "cp38-* cp39-* cp310-* cp311-* cp312-* cp313-*"
48
+ CIBW_BUILD: "cp39-* cp310-* cp311-* cp312-* cp313-*"
49
49
  # Skip 32-bit and musl (uncommon for scientific Python)
50
50
  CIBW_SKIP: "*-win32 *-manylinux_i686 *-musllinux*"
51
51
  # maturin needs Rust in the build container
@@ -80,9 +80,9 @@ jobs:
80
80
  # missing OpenBLAS (this broke the v3.6.0 first build attempt - the
81
81
  # skip is load-bearing, do not remove it). Linux import + full-suite
82
82
  # coverage lives in .github/workflows/tests.yml instead.
83
- # Also skip macOS (MPFR symbol issue) and cp38/cp39 (dependency
83
+ # Also skip macOS (MPFR symbol issue) and cp39 (dependency
84
84
  # ilt-inversion may not have matching wheels on PyPI yet).
85
- CIBW_TEST_SKIP: "*-manylinux* *-macosx* cp38-* cp39-*"
85
+ CIBW_TEST_SKIP: "*-manylinux* *-macosx* cp39-*"
86
86
 
87
87
  - uses: actions/upload-artifact@v6
88
88
  with:
@@ -108,7 +108,7 @@ jobs:
108
108
  uses: pypa/cibuildwheel@v2.23
109
109
  env:
110
110
  CIBW_BUILD_FRONTEND: "build"
111
- CIBW_BUILD: "cp38-* cp39-* cp310-* cp311-* cp312-* cp313-*"
111
+ CIBW_BUILD: "cp39-* cp310-* cp311-* cp312-* cp313-*"
112
112
  CIBW_ARCHS_MACOS: "x86_64"
113
113
  CIBW_TEST_COMMAND: >
114
114
  python -c "from pyrestoolbox._accelerator import get_status; s = get_status(); print(s); assert s['rust_available'], f'Rust not loaded: {s}'"
@@ -63,6 +63,32 @@ jobs:
63
63
  - name: Run full test suite (Rust + parity)
64
64
  run: python3 -m pytest pyrestoolbox/tests/ -q
65
65
 
66
+ # ── MCP server (separate distribution in mcp/) on both SDK majors ────
67
+ # The server picks FastMCP (1.x) or MCPServer (2.x) at import; test both so
68
+ # an SDK release that breaks either path fails here, not in a deployment.
69
+ test-mcp:
70
+ name: MCP server (${{ matrix.mcp }})
71
+ runs-on: ubuntu-latest
72
+ strategy:
73
+ fail-fast: false
74
+ matrix:
75
+ mcp: ["mcp>=1.2,<2", "mcp>=2,<3"]
76
+ steps:
77
+ - uses: actions/checkout@v5
78
+
79
+ - uses: actions/setup-python@v6
80
+ with:
81
+ python-version: "3.12"
82
+
83
+ - name: Install dependencies
84
+ run: pip install numpy scipy pandas tabulate openpyxl mpmath ilt-inversion pytest "${{ matrix.mcp }}"
85
+
86
+ # Library from the source tree (pure Python), server from mcp/.
87
+ - name: Run MCP tests
88
+ env:
89
+ PYRESTOOLBOX_NO_RUST: "1"
90
+ run: PYTHONPATH="$PWD:$PWD/mcp" python3 -m pytest mcp/tests/ -q
91
+
66
92
  # ── Complexity ratchet (new code only; existing offenders baselined) ─
67
93
  complexity:
68
94
  name: Complexity ratchet
@@ -80,7 +106,7 @@ jobs:
80
106
  - name: Check cyclomatic complexity against baseline
81
107
  run: python3 .github/scripts/check_complexity.py
82
108
 
83
- # ── Rust lint ratchet (clippy clean; any new warning fails) ─────────
109
+ # ── Rust lint ratchet (clippy clean; any new warning fails) and unit tests ─
84
110
  rust-lint:
85
111
  name: Clippy
86
112
  runs-on: ubuntu-latest
@@ -96,3 +122,6 @@ jobs:
96
122
 
97
123
  - name: Clippy
98
124
  run: cargo clippy --all-targets -- -D warnings
125
+
126
+ - name: Rust unit tests
127
+ run: cargo test --release
@@ -57,3 +57,6 @@ pyrestoolbox-mcp-email.txt
57
57
  DEFECTS-FOUND-*.md
58
58
  PORT-SPEC-*.md
59
59
  *.zip
60
+
61
+ # Local primary-source library (copyrighted papers and its index) - never published
62
+ papers/
@@ -152,7 +152,7 @@ dependencies = [
152
152
 
153
153
  [[package]]
154
154
  name = "pyrestoolbox-native"
155
- version = "3.7.7"
155
+ version = "3.8.3"
156
156
  dependencies = [
157
157
  "pyo3",
158
158
  "rug",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "pyrestoolbox-native"
3
- version = "3.7.7"
3
+ version = "3.8.3"
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.7.7
3
+ Version: 3.8.3
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+)
@@ -12,7 +12,6 @@ Requires-Dist: tabulate
12
12
  Requires-Dist: ilt-inversion
13
13
  Requires-Dist: mpmath
14
14
  Requires-Dist: gmpy2
15
- Requires-Dist: python-flint
16
15
  Requires-Dist: openpyxl
17
16
  License-File: LICENSE
18
17
  Summary: pyResToolbox - A collection of Reservoir Engineering Utilities
@@ -20,7 +19,7 @@ Keywords: restoolbox,petroleum,reservoir
20
19
  Home-Page: https://github.com/mwburgoyne/pyResToolbox
21
20
  Author-email: "Mark W. Burgoyne" <mark.w.burgoyne@gmail.com>
22
21
  License: GPL-3.0-or-later
23
- Requires-Python: >=3.8
22
+ Requires-Python: >=3.9
24
23
  Description-Content-Type: text/x-rst; charset=UTF-8
25
24
  Project-URL: Homepage, https://github.com/mwburgoyne/pyResToolbox
26
25
 
@@ -35,7 +34,7 @@ A collection of Reservoir Engineering Utilities
35
34
  This set of functions focuses on those that the author uses often while crafting programming solutions.
36
35
  These are the scripts that are often copy/pasted from previous work - sometimes slightly modified - resulting in a trail of slightly different versions over the years. Some attempt has been made here to make this implementation flexible enough such that it can be relied on as-is going forward.
37
36
 
38
- Note: Version 3.0 consolidates simulation-oriented functions under the simtools module, adds nodal analysis (VLP/IPR), VFP table generation, relative permeability curve fitting, and Eclipse METRIC unit support across all modules. Version 3.0.4 adds decline curve analysis, material balance, method recommendations, and sensitivity analysis.
37
+ Modules: gas, oil, brine, nodal (VLP/IPR, VFP tables), simtools (black-oil, PVTW, rel-perm, aquifer and deck tools), dca (decline curves), matbal (material balance), layer, library, recommend and sensitivity. Every module accepts Eclipse METRIC units with ``metric=True``; the full documentation ships inside the package, and ``pyrestoolbox.docs_dir()`` returns its location for offline reading.
39
38
 
40
39
  Includes functions to perform calculations including;
41
40
 
@@ -46,7 +45,7 @@ Includes functions to perform calculations including;
46
45
  - Nodal analysis operating point determination
47
46
  - Eclipse VFP table generation (VFPPROD and VFPINJ keywords)
48
47
  - PVT Calculations for oil
49
- - PVT calculation for gas, including up to 100% inerts for CO2, H2S, N2 and H2
48
+ - PVT calculation for gas, including up to 100% inerts for CO2, H2S, N2, H2 and He
50
49
  - Gas caloric properties (enthalpy, Cp, Cv, Joule-Thomson coefficient) from the BNS tuned Peng Robinson EOS
51
50
  - Gas hydrate formation prediction with thermodynamic inhibitor calculations
52
51
  - Return critical parameters for typical components
@@ -289,13 +288,11 @@ Or creating black oil table information for oil
289
288
  >>>
290
289
  >>> plt.tight_layout()
291
290
  >>> plt.show()
292
- Iteratively solving for Rsb fraction to use in order to harmonize user specified Pb and Rsb
293
-
294
- Stock Tank Oil Density: 52.09203539823009 lb/cuft
295
- Stock Tank Gas Density: 0.052046870460837856 lb/cuft
296
- Reservoir Water Density: 61.40223160167964 lb/cuft
291
+ Stock Tank Oil Density: 52.06448672566371 lb/cuft
292
+ Stock Tank Gas Density: 0.05204687045843109 lb/cuft
293
+ Reservoir Water Density: 61.37100825498743 lb/cuft
297
294
  Reservoir Water Compressibility: 2.930237693350768e-06 1/psi
298
- Reservoir Water Viscosity: 0.3640686136171888 cP
295
+ Reservoir Water Viscosity: 0.36386395924173587 cP
299
296
 
300
297
  .. image:: https://raw.githubusercontent.com/mwburgoyne/pyResToolbox/main/pyrestoolbox/docs/img/bot.png
301
298
  :alt: Black Oil Properties
@@ -374,17 +371,17 @@ With ability to generate Live Oil PVTO style table data as well
374
371
  >>> ..
375
372
  >>> plt.show()
376
373
  Pb (psia): 4500
377
- Bob (rb/stb): 1.6072798403441817
378
- Rsb (mscf/stb): 1.2863705330979234
379
- Rsb Scaling Required: 0.9713981737449556
380
- Visob (cP): 0.3422139569449832
381
- Cob (1/psi): 5.711273668114706e-05
382
-
383
- Stock Tank Oil Density: 52.05522123893805 lb/cuft
384
- Stock Tank Gas Density: 0.052025361717109773 lb/cuft
385
- Reservoir Water Density: 61.40223160167964 lb/cuft
374
+ Bob (rb/stb): 1.5372158966466267
375
+ Rsb (mscf/stb): 1.137900924344287
376
+ Rsb Scaling Required: 1.0362710951888936
377
+ Visob (cP): 0.36663121233374113
378
+ Cob (1/psi): 2.0042955593519084e-05
379
+
380
+ Stock Tank Oil Density: 52.06448672566371 lb/cuft
381
+ Stock Tank Gas Density: 0.05204687045843109 lb/cuft
382
+ Reservoir Water Density: 61.37100825498743 lb/cuft
386
383
  Reservoir Water Compressibility: 2.930237693350768e-06 1/psi
387
- Reservoir Water Viscosity: 0.3640686136171888 cP
384
+ Reservoir Water Viscosity: 0.36386395924173587 cP
388
385
 
389
386
  .. image:: https://raw.githubusercontent.com/mwburgoyne/pyResToolbox/main/pyrestoolbox/docs/img/bot_PVTO.png
390
387
  :alt: Live Oil Properties
@@ -9,7 +9,7 @@ A collection of Reservoir Engineering Utilities
9
9
  This set of functions focuses on those that the author uses often while crafting programming solutions.
10
10
  These are the scripts that are often copy/pasted from previous work - sometimes slightly modified - resulting in a trail of slightly different versions over the years. Some attempt has been made here to make this implementation flexible enough such that it can be relied on as-is going forward.
11
11
 
12
- Note: Version 3.0 consolidates simulation-oriented functions under the simtools module, adds nodal analysis (VLP/IPR), VFP table generation, relative permeability curve fitting, and Eclipse METRIC unit support across all modules. Version 3.0.4 adds decline curve analysis, material balance, method recommendations, and sensitivity analysis.
12
+ Modules: gas, oil, brine, nodal (VLP/IPR, VFP tables), simtools (black-oil, PVTW, rel-perm, aquifer and deck tools), dca (decline curves), matbal (material balance), layer, library, recommend and sensitivity. Every module accepts Eclipse METRIC units with ``metric=True``; the full documentation ships inside the package, and ``pyrestoolbox.docs_dir()`` returns its location for offline reading.
13
13
 
14
14
  Includes functions to perform calculations including;
15
15
 
@@ -20,7 +20,7 @@ Includes functions to perform calculations including;
20
20
  - Nodal analysis operating point determination
21
21
  - Eclipse VFP table generation (VFPPROD and VFPINJ keywords)
22
22
  - PVT Calculations for oil
23
- - PVT calculation for gas, including up to 100% inerts for CO2, H2S, N2 and H2
23
+ - PVT calculation for gas, including up to 100% inerts for CO2, H2S, N2, H2 and He
24
24
  - Gas caloric properties (enthalpy, Cp, Cv, Joule-Thomson coefficient) from the BNS tuned Peng Robinson EOS
25
25
  - Gas hydrate formation prediction with thermodynamic inhibitor calculations
26
26
  - Return critical parameters for typical components
@@ -263,13 +263,11 @@ Or creating black oil table information for oil
263
263
  >>>
264
264
  >>> plt.tight_layout()
265
265
  >>> plt.show()
266
- Iteratively solving for Rsb fraction to use in order to harmonize user specified Pb and Rsb
267
-
268
- Stock Tank Oil Density: 52.09203539823009 lb/cuft
269
- Stock Tank Gas Density: 0.052046870460837856 lb/cuft
270
- Reservoir Water Density: 61.40223160167964 lb/cuft
266
+ Stock Tank Oil Density: 52.06448672566371 lb/cuft
267
+ Stock Tank Gas Density: 0.05204687045843109 lb/cuft
268
+ Reservoir Water Density: 61.37100825498743 lb/cuft
271
269
  Reservoir Water Compressibility: 2.930237693350768e-06 1/psi
272
- Reservoir Water Viscosity: 0.3640686136171888 cP
270
+ Reservoir Water Viscosity: 0.36386395924173587 cP
273
271
 
274
272
  .. image:: https://raw.githubusercontent.com/mwburgoyne/pyResToolbox/main/pyrestoolbox/docs/img/bot.png
275
273
  :alt: Black Oil Properties
@@ -348,17 +346,17 @@ With ability to generate Live Oil PVTO style table data as well
348
346
  >>> ..
349
347
  >>> plt.show()
350
348
  Pb (psia): 4500
351
- Bob (rb/stb): 1.6072798403441817
352
- Rsb (mscf/stb): 1.2863705330979234
353
- Rsb Scaling Required: 0.9713981737449556
354
- Visob (cP): 0.3422139569449832
355
- Cob (1/psi): 5.711273668114706e-05
356
-
357
- Stock Tank Oil Density: 52.05522123893805 lb/cuft
358
- Stock Tank Gas Density: 0.052025361717109773 lb/cuft
359
- Reservoir Water Density: 61.40223160167964 lb/cuft
349
+ Bob (rb/stb): 1.5372158966466267
350
+ Rsb (mscf/stb): 1.137900924344287
351
+ Rsb Scaling Required: 1.0362710951888936
352
+ Visob (cP): 0.36663121233374113
353
+ Cob (1/psi): 2.0042955593519084e-05
354
+
355
+ Stock Tank Oil Density: 52.06448672566371 lb/cuft
356
+ Stock Tank Gas Density: 0.05204687045843109 lb/cuft
357
+ Reservoir Water Density: 61.37100825498743 lb/cuft
360
358
  Reservoir Water Compressibility: 2.930237693350768e-06 1/psi
361
- Reservoir Water Viscosity: 0.3640686136171888 cP
359
+ Reservoir Water Viscosity: 0.36386395924173587 cP
362
360
 
363
361
  .. image:: https://raw.githubusercontent.com/mwburgoyne/pyResToolbox/main/pyrestoolbox/docs/img/bot_PVTO.png
364
362
  :alt: Live Oil Properties
@@ -7,7 +7,7 @@ FROM python:3.11-slim
7
7
 
8
8
  # Pin the library version for reproducible corporate deployments; bump
9
9
  # deliberately and rebuild.
10
- ARG PYRESTOOLBOX_VERSION=3.7.0
10
+ ARG PYRESTOOLBOX_VERSION=3.8.2
11
11
 
12
12
  WORKDIR /app
13
13
  COPY . /app/mcp
@@ -66,8 +66,7 @@ pyrestoolbox-mcp --transport streamable-http --host 0.0.0.0 --port 8000
66
66
 
67
67
  It is stateless (no session affinity needed behind a load balancer) and
68
68
  serves the MCP endpoint at `/mcp`. A `Dockerfile` is included; put an API
69
- gateway in front for authentication. See `DEPLOYMENT.md` for the platform
70
- team one-pager.
69
+ gateway in front for authentication.
71
70
 
72
71
  ## Tests
73
72
 
@@ -80,8 +79,16 @@ PYTHONPATH=<repo>:<repo>/mcp python3 -m pytest mcp/tests/ -q
80
79
  - Units default to oilfield (psia, deg F, ft, mD, cP); pass `metric: true`
81
80
  where the function supports it. The plyasunov module is SI (K, MPa).
82
81
  - The oil module is scalar-only; gas and brine functions accept lists.
83
- - Stateful classes (`GasPVT`, `CO2_Brine_Mixture`, `SoreideWhitson`,
84
- `DeclineResult`) are not exposed through `call` - the one-shot wrapper
85
- tools cover the common workflows.
82
+ - Gas rates are Mscf/d everywhere (sm3/d with `metric: true`).
83
+ - Functions that take objects are callable through `call` with those objects
84
+ written as JSON objects of their constructor keywords: `completion`
85
+ (`nodal.Completion`, with an optional `segments` list of `WellSegment`
86
+ objects), `reservoir`, `gas_pvt`, `oil_pvt`, `result` (the object a
87
+ `fit_decline` or `fit_ratio` call returned), `ratios`, and `func` as a
88
+ `'module.function'` name for `sensitivity.sweep`/`tornado`. For example
89
+ `call('nodal.fbhp', {"thp": 500, "well_type": "gas", "qg_mscfd": 5000,
90
+ "completion": {"tid": 2.441, "length": 10000, "tht": 100, "bht": 200}})`.
91
+ Classes themselves are not called directly; the one-shot wrapper tools
92
+ cover the common stateful workflows.
86
93
  - File-writing simtools functions keep their `export=False` defaults, so
87
94
  calls return table text rather than touching disk.
@@ -11,8 +11,8 @@ authors = [{name = "Mark W. Burgoyne", email = "mark.w.burgoyne@gmail.com"}]
11
11
  keywords = ["mcp", "petroleum", "reservoir", "pyrestoolbox"]
12
12
  requires-python = ">=3.10"
13
13
  dependencies = [
14
- "mcp>=1.2",
15
- "pyrestoolbox>=3.7",
14
+ "mcp>=1.2,<3",
15
+ "pyrestoolbox>=3.8.2",
16
16
  ]
17
17
  readme = "README.md"
18
18
 
@@ -17,7 +17,12 @@ as MCP resources (docs://gas, docs://oil, ...).
17
17
  import importlib
18
18
  import inspect
19
19
 
20
- from mcp.server.fastmcp import FastMCP
20
+ try: # mcp >= 2 renamed FastMCP to MCPServer
21
+ from mcp.server.mcpserver import MCPServer as _MCPServer
22
+ _MCP_V2 = True
23
+ except ImportError: # mcp 1.x
24
+ from mcp.server.fastmcp import FastMCP as _MCPServer
25
+ _MCP_V2 = False
21
26
 
22
27
  from pyrestoolbox_mcp.serialize import to_jsonable
23
28
 
@@ -37,7 +42,7 @@ ALLOWED_MODULES = {
37
42
  "sensitivity": "Parameter sweeps and tornado analysis",
38
43
  }
39
44
 
40
- mcp = FastMCP(
45
+ mcp = _MCPServer(
41
46
  "pyrestoolbox",
42
47
  instructions=(
43
48
  "Petroleum/reservoir engineering calculations from the pyrestoolbox "
@@ -53,6 +58,10 @@ mcp = FastMCP(
53
58
  "Fahrenheit value to `degf` with metric=True converts it twice and "
54
59
  "returns a wrong answer silently. Standard volumes are always at "
55
60
  "60 deg F and 14.696 psia, so metric sm3 is on that basis. "
61
+ "Gas rates are Mscf/d everywhere (sm3/d with metric=True). "
62
+ "Functions that take objects (Completion, Reservoir, GasPVT, OilPVT, "
63
+ "decline results) accept them through call() as JSON objects of their "
64
+ "constructor keywords; see the call tool description. "
56
65
  "Full module documentation is available as docs:// resources."
57
66
  ),
58
67
  )
@@ -147,8 +156,23 @@ def call(name: str, arguments: dict = {}) -> dict:
147
156
  Correlation methods are strings (e.g. "zmethod": "DAK"); an invalid
148
157
  method string returns an error listing the valid options. Gas and brine
149
158
  functions accept lists for pressure-like inputs; oil functions are
150
- scalar-only. Classes cannot be called here - use the one-shot wrapper
151
- tools (co2_brine_props, sw_brine_props, fit_and_forecast) instead.
159
+ scalar-only. Gas rates are Mscf/d (sm3/d with metric=True).
160
+
161
+ Object arguments are passed as JSON objects of their constructor keywords
162
+ and built here (describe the class for its keywords):
163
+ completion -> nodal.Completion (a "segments" list of objects -> WellSegment)
164
+ reservoir -> nodal.Reservoir
165
+ gas_pvt -> gas.GasPVT
166
+ oil_pvt -> oil.OilPVT
167
+ result -> dca.DeclineResult (forecast) or dca.RatioResult (ratio_forecast);
168
+ pass the object a fit_decline / fit_ratio call returned
169
+ ratios -> {name: RatioResult object}
170
+ func -> a 'module.function' name (sensitivity.sweep / tornado); objects
171
+ inside base_kwargs are built by the same rules
172
+ e.g. call('nodal.fbhp', {"thp": 500, "well_type": "gas", "qg_mscfd": 5000,
173
+ "completion": {"tid": 2.441, "length": 10000, "tht": 100, "bht": 200}}).
174
+ Classes themselves cannot be called here; one-shot wrappers
175
+ (co2_brine_props, sw_brine_props, fit_and_forecast) cover the common cases.
152
176
  """
153
177
  _, obj = _resolve(name)
154
178
  if inspect.isclass(obj):
@@ -159,14 +183,79 @@ def call(name: str, arguments: dict = {}) -> dict:
159
183
  )
160
184
  if not callable(obj):
161
185
  raise ValueError(f"{name} is not callable (it is {type(obj).__name__})")
162
- result = obj(**arguments)
186
+ result = obj(**_build_objects(obj, arguments))
163
187
  return {"result": to_jsonable(result)}
164
188
 
165
189
 
190
+ def _library_class(dotted: str):
191
+ module, cls = dotted.split(".")
192
+ return getattr(_get_module(module), cls)
193
+
194
+
195
+ # Keyword -> library class built from a JSON object. The library names these
196
+ # parameters consistently, so one table covers every function that takes them.
197
+ _OBJECT_PARAMS = {
198
+ "completion": "nodal.Completion",
199
+ "reservoir": "nodal.Reservoir",
200
+ "gas_pvt": "gas.GasPVT",
201
+ "oil_pvt": "oil.OilPVT",
202
+ }
203
+
204
+
205
+ def _build_objects(fn, arguments: dict) -> dict:
206
+ """Turn JSON objects in `arguments` into the library objects fn expects.
207
+
208
+ Raises ValueError naming the parameter and class when construction fails,
209
+ so an agent learns which keywords to fix instead of an AttributeError from
210
+ deep inside the library.
211
+ """
212
+ try:
213
+ annotations = {k: str(v.annotation) for k, v in inspect.signature(fn).parameters.items()}
214
+ except (TypeError, ValueError):
215
+ annotations = {}
216
+ out = {}
217
+ for key, value in arguments.items():
218
+ out[key] = _build_one(key, value, annotations.get(key, ""))
219
+ return out
220
+
221
+
222
+ def _build_one(key, value, annotation):
223
+ if key == "func" and isinstance(value, str):
224
+ _, fn = _resolve(value)
225
+ return fn
226
+ if key == "base_kwargs" and isinstance(value, dict):
227
+ return {k: _build_one(k, v, "") for k, v in value.items()}
228
+ if not isinstance(value, dict):
229
+ return value
230
+ if key == "ratios":
231
+ return {name: _construct("dca.RatioResult", key, spec) for name, spec in value.items()}
232
+ if key == "result":
233
+ dotted = "dca.RatioResult" if "RatioResult" in annotation else "dca.DeclineResult"
234
+ return _construct(dotted, key, value)
235
+ if key in _OBJECT_PARAMS:
236
+ if key == "completion" and isinstance(value.get("segments"), list):
237
+ value = dict(value, segments=[
238
+ _construct("nodal.WellSegment", "completion.segments", seg)
239
+ if isinstance(seg, dict) else seg for seg in value["segments"]])
240
+ return _construct(_OBJECT_PARAMS[key], key, value)
241
+ return value
242
+
243
+
244
+ def _construct(dotted, key, spec):
245
+ cls = _library_class(dotted)
246
+ try:
247
+ return cls(**spec)
248
+ except TypeError as exc:
249
+ raise ValueError(
250
+ f"Could not build {dotted} for '{key}' from {sorted(spec)}: {exc}. "
251
+ f"Use describe({dotted!r}) for its keywords."
252
+ ) from exc
253
+
254
+
166
255
  @mcp.tool()
167
256
  def recommend_methods(sg: float = 0.65, co2: float = 0, h2s: float = 0,
168
257
  n2: float = 0, h2: float = 0, api: float | None = None,
169
- deviation: float = 0, well_type: str = "gas") -> dict:
258
+ deviation: float = 0, well_type: str = "gas", he: float = 0) -> dict:
170
259
  """Recommend correlation methods for a fluid/well, with rationale.
171
260
 
172
261
  Composition fractions are molar. api: stock tank oil gravity (include to
@@ -179,7 +268,7 @@ def recommend_methods(sg: float = 0.65, co2: float = 0, h2s: float = 0,
179
268
  from pyrestoolbox import recommend
180
269
  recs = recommend.recommend_methods(sg=sg, co2=co2, h2s=h2s, n2=n2, h2=h2,
181
270
  api=api, deviation=deviation,
182
- well_type=well_type)
271
+ well_type=well_type, he=he)
183
272
  return to_jsonable(recs)
184
273
 
185
274
 
@@ -207,12 +296,12 @@ def co2_brine_props(pres: float, temp: float, ppm: float = 0,
207
296
  def sw_brine_props(pres: float, temp: float, ppm: float = 0,
208
297
  y_CO2: float = 0, y_H2S: float = 0, y_N2: float = 0,
209
298
  y_H2: float = 0, sg: float = 0.65, cw_sat: bool = False,
210
- metric: bool = False) -> dict:
299
+ metric: bool = False, y_He: float = 0) -> dict:
211
300
  """Multicomponent gas-saturated brine properties (Soreide-Whitson VLE).
212
301
 
213
302
  pres: pressure (psia, or barsa if metric=True). temp: temperature
214
303
  (deg F, or deg C if metric=True). ppm: NaCl-equivalent salinity.
215
- y_*: molar fractions of CO2/H2S/N2/H2 in the equilibrium gas; the
304
+ y_*: molar fractions of CO2/H2S/N2/H2/He in the equilibrium gas; the
216
305
  remainder is hydrocarbon gas of specific gravity sg. Returns aqueous
217
306
  composition, brine density/viscosity triplets, Rs, water content and
218
307
  compressibilities.
@@ -220,7 +309,7 @@ def sw_brine_props(pres: float, temp: float, ppm: float = 0,
220
309
  from pyrestoolbox import brine
221
310
  sw = brine.SoreideWhitson(pres=pres, temp=temp, ppm=ppm, y_CO2=y_CO2,
222
311
  y_H2S=y_H2S, y_N2=y_N2, y_H2=y_H2, sg=sg,
223
- cw_sat=cw_sat, metric=metric)
312
+ cw_sat=cw_sat, metric=metric, y_He=y_He)
224
313
  keys = ("x", "bDen", "bVis", "bw", "Rs", "Rs_total", "water_content",
225
314
  "Cf_usat", "Cf_sat")
226
315
  return {k: to_jsonable(getattr(sw, k, None)) for k in keys}
@@ -298,13 +387,18 @@ def build_parser():
298
387
 
299
388
  def main():
300
389
  args = build_parser().parse_args()
301
- if args.transport == "streamable-http":
302
- mcp.settings.host = args.host
303
- mcp.settings.port = args.port
304
- # Independent request handling; no server-side session affinity needed
305
- # behind a load balancer.
306
- mcp.settings.stateless_http = True
307
- mcp.run(transport=args.transport)
390
+ if args.transport != "streamable-http":
391
+ mcp.run(transport=args.transport)
392
+ return
393
+ # stateless_http: independent request handling; no server-side session
394
+ # affinity needed behind a load balancer.
395
+ http = {"host": args.host, "port": args.port, "stateless_http": True}
396
+ if _MCP_V2:
397
+ mcp.run(transport=args.transport, **http)
398
+ else: # 1.x reads these from settings, not run()
399
+ for key, value in http.items():
400
+ setattr(mcp.settings, key, value)
401
+ mcp.run(transport=args.transport)
308
402
 
309
403
 
310
404
  if __name__ == "__main__":