pyrestoolbox 3.6.0__tar.gz → 3.7.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/.github/workflows/build-wheels.yml +15 -15
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/.github/workflows/tests.yml +4 -4
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/.gitignore +7 -6
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/Cargo.lock +1 -1
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/Cargo.toml +1 -1
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/PKG-INFO +1 -1
- pyrestoolbox-3.7.1/mcp/DEPLOYMENT.md +53 -0
- pyrestoolbox-3.7.1/mcp/Dockerfile +23 -0
- pyrestoolbox-3.7.1/mcp/README.md +87 -0
- pyrestoolbox-3.7.1/mcp/pyproject.toml +26 -0
- pyrestoolbox-3.7.1/mcp/pyrestoolbox_mcp/__init__.py +3 -0
- pyrestoolbox-3.7.1/mcp/pyrestoolbox_mcp/serialize.py +50 -0
- pyrestoolbox-3.7.1/mcp/pyrestoolbox_mcp/server.py +295 -0
- pyrestoolbox-3.7.1/mcp/tests/test_server.py +183 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyproject.toml +1 -1
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/__init__.py +23 -2
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/brine/_lib_vle_engine.py +98 -22
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/brine/brine.py +11 -12
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/dca/dca.py +575 -19
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/brine.rst +3 -3
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/changelist.rst +18 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/dca.rst +372 -8
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/gas.rst +9 -3
- pyrestoolbox-3.7.1/pyrestoolbox/docs/index.rst +62 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/layer.rst +2 -2
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/nodal.rst +9 -6
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/oil.rst +7 -8
- pyrestoolbox-3.7.1/pyrestoolbox/docs/plyasunov.rst +230 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/simtools.rst +7 -3
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/gas/gas.py +18 -28
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/layer/layer.py +1 -1
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/nodal/nodal.py +2 -2
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/plyasunov/plyasunov_model.py +9 -2
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/zfactor/mod.rs +2 -33
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/LICENSE +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/MANIFEST.in +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/README.rst +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/ResToolbox/privacy_policy.md +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/benchmark_rust_vs_python.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/build_pure_python.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/_accelerator.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/brine/__init__.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/brine/_lib_salting_library.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/classes/__init__.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/classes/classes.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/constants/__init__.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/constants/constants.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/dca/__init__.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/examples.ipynb +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/img/bot.png +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/img/bot_PVTO.png +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/img/bot_img.png +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/img/dry_gas.png +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/img/grid_sat_df.png +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/img/influence.png +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/img/properties_df.png +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/img/sgof.png +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/img/swof.png +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/library.rst +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/matbal.rst +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/nodal_examples.ipynb +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/nodal_hydrate_demo.ipynb +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/recommend.rst +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/docs/sensitivity.rst +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/gas/__init__.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/gas/_hydrate.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/layer/__init__.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/library/__init__.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/library/component_library.xlsx +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/library/library.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/matbal/__init__.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/matbal/matbal.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/nodal/__init__.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/oil/__init__.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/oil/_compressibility.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/oil/_constants.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/oil/_correlations.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/oil/_density.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/oil/_harmonize.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/oil/_pvt_class.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/oil/_rate.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/oil/_separator.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/oil/_tables.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/oil/_utils.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/plyasunov/__init__.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/plyasunov/iapws_if97.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/plyasunov/water_properties.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/recommend/__init__.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/recommend/recommend.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/sensitivity/__init__.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/sensitivity/sensitivity.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/shared_fns/__init__.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/shared_fns/shared_fns.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/simtools/__init__.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/simtools/_aquifer.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/simtools/_decks.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/simtools/_pvt_tables.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/simtools/_relperm.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/simtools/_vfp.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/simtools/simtools.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/validate/__init__.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/pyrestoolbox/validate/validate.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/setup.cfg +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/setup.py +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/bessel.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/critical_properties/mod.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/dca/hyperbolic.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/dca/mod.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/dca/ransac.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/gas_viscosity/mod.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/gwr.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/lib.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/matbal/mod.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/matbal/objective.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/oil/density.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/oil/mod.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/pseudopressure.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/spycher_pruess/mod.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/spycher_pruess/solubility.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/vle/alpha.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/vle/bip.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/vle/components.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/vle/eos.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/vle/flash.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/vle/fugacity.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/vle/k_init.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/vle/mod.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/vle/rachford_rice.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/vlp/constants.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/vlp/friction.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/vlp/holdup_bb.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/vlp/holdup_gray.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/vlp/holdup_wg.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/vlp/ift.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/vlp/march.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/vlp/mod.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/vlp/pvt_helpers.rs +0 -0
- {pyrestoolbox-3.6.0 → pyrestoolbox-3.7.1}/src/vlp/static_column.rs +0 -0
|
@@ -20,9 +20,9 @@ jobs:
|
|
|
20
20
|
matrix:
|
|
21
21
|
os: [ubuntu-latest, macos-14, windows-latest]
|
|
22
22
|
steps:
|
|
23
|
-
- uses: actions/checkout@
|
|
23
|
+
- uses: actions/checkout@v5
|
|
24
24
|
|
|
25
|
-
- uses: actions/setup-python@
|
|
25
|
+
- uses: actions/setup-python@v6
|
|
26
26
|
with:
|
|
27
27
|
python-version: "3.12"
|
|
28
28
|
|
|
@@ -84,7 +84,7 @@ jobs:
|
|
|
84
84
|
# ilt-inversion may not have matching wheels on PyPI yet).
|
|
85
85
|
CIBW_TEST_SKIP: "*-manylinux* *-macosx* cp38-* cp39-*"
|
|
86
86
|
|
|
87
|
-
- uses: actions/upload-artifact@
|
|
87
|
+
- uses: actions/upload-artifact@v6
|
|
88
88
|
with:
|
|
89
89
|
name: wheels-${{ matrix.os }}
|
|
90
90
|
path: ./wheelhouse/*.whl
|
|
@@ -95,9 +95,9 @@ jobs:
|
|
|
95
95
|
runs-on: macos-13
|
|
96
96
|
if: false # Enable when macos-13 runners are available, or use cross-compilation
|
|
97
97
|
steps:
|
|
98
|
-
- uses: actions/checkout@
|
|
98
|
+
- uses: actions/checkout@v5
|
|
99
99
|
|
|
100
|
-
- uses: actions/setup-python@
|
|
100
|
+
- uses: actions/setup-python@v6
|
|
101
101
|
with:
|
|
102
102
|
python-version: "3.12"
|
|
103
103
|
|
|
@@ -114,7 +114,7 @@ jobs:
|
|
|
114
114
|
python -c "from pyrestoolbox._accelerator import get_status; s = get_status(); print(s); assert s['rust_available'], f'Rust not loaded: {s}'"
|
|
115
115
|
CIBW_TEST_REQUIRES: "numpy"
|
|
116
116
|
|
|
117
|
-
- uses: actions/upload-artifact@
|
|
117
|
+
- uses: actions/upload-artifact@v6
|
|
118
118
|
with:
|
|
119
119
|
name: wheels-macos-x86
|
|
120
120
|
path: ./wheelhouse/*.whl
|
|
@@ -124,9 +124,9 @@ jobs:
|
|
|
124
124
|
name: Build pure-Python wheel
|
|
125
125
|
runs-on: ubuntu-latest
|
|
126
126
|
steps:
|
|
127
|
-
- uses: actions/checkout@
|
|
127
|
+
- uses: actions/checkout@v5
|
|
128
128
|
|
|
129
|
-
- uses: actions/setup-python@
|
|
129
|
+
- uses: actions/setup-python@v6
|
|
130
130
|
with:
|
|
131
131
|
python-version: "3.12"
|
|
132
132
|
|
|
@@ -136,7 +136,7 @@ jobs:
|
|
|
136
136
|
- name: Build pure-Python wheel
|
|
137
137
|
run: python build_pure_python.py
|
|
138
138
|
|
|
139
|
-
- uses: actions/upload-artifact@
|
|
139
|
+
- uses: actions/upload-artifact@v6
|
|
140
140
|
with:
|
|
141
141
|
name: wheels-pure-python
|
|
142
142
|
path: ./dist/*.whl
|
|
@@ -146,9 +146,9 @@ jobs:
|
|
|
146
146
|
name: Build source distribution
|
|
147
147
|
runs-on: ubuntu-latest
|
|
148
148
|
steps:
|
|
149
|
-
- uses: actions/checkout@
|
|
149
|
+
- uses: actions/checkout@v5
|
|
150
150
|
|
|
151
|
-
- uses: actions/setup-python@
|
|
151
|
+
- uses: actions/setup-python@v6
|
|
152
152
|
with:
|
|
153
153
|
python-version: "3.12"
|
|
154
154
|
|
|
@@ -161,7 +161,7 @@ jobs:
|
|
|
161
161
|
- name: Build sdist
|
|
162
162
|
run: maturin sdist --out dist
|
|
163
163
|
|
|
164
|
-
- uses: actions/upload-artifact@
|
|
164
|
+
- uses: actions/upload-artifact@v6
|
|
165
165
|
with:
|
|
166
166
|
name: sdist
|
|
167
167
|
path: ./dist/*.tar.gz
|
|
@@ -179,7 +179,7 @@ jobs:
|
|
|
179
179
|
id-token: write # trusted publishing
|
|
180
180
|
contents: write # create the GitHub Release
|
|
181
181
|
steps:
|
|
182
|
-
- uses: actions/download-artifact@
|
|
182
|
+
- uses: actions/download-artifact@v7
|
|
183
183
|
with:
|
|
184
184
|
path: dist
|
|
185
185
|
merge-multiple: true
|
|
@@ -190,7 +190,7 @@ jobs:
|
|
|
190
190
|
packages-dir: dist/
|
|
191
191
|
|
|
192
192
|
# ── Create a notes-only GitHub Release (no binaries; PyPI is canonical) ──
|
|
193
|
-
- uses: actions/checkout@
|
|
193
|
+
- uses: actions/checkout@v5
|
|
194
194
|
|
|
195
195
|
- name: Extract release notes from changelist
|
|
196
196
|
run: |
|
|
@@ -218,7 +218,7 @@ jobs:
|
|
|
218
218
|
PY
|
|
219
219
|
|
|
220
220
|
- name: Create GitHub Release
|
|
221
|
-
uses: softprops/action-gh-release@
|
|
221
|
+
uses: softprops/action-gh-release@v3
|
|
222
222
|
with:
|
|
223
223
|
name: ${{ github.ref_name }}
|
|
224
224
|
body_path: release_notes.md
|
|
@@ -15,9 +15,9 @@ jobs:
|
|
|
15
15
|
name: Pure Python (PYRESTOOLBOX_NO_RUST=1)
|
|
16
16
|
runs-on: ubuntu-latest
|
|
17
17
|
steps:
|
|
18
|
-
- uses: actions/checkout@
|
|
18
|
+
- uses: actions/checkout@v5
|
|
19
19
|
|
|
20
|
-
- uses: actions/setup-python@
|
|
20
|
+
- uses: actions/setup-python@v6
|
|
21
21
|
with:
|
|
22
22
|
python-version: "3.10"
|
|
23
23
|
|
|
@@ -34,9 +34,9 @@ jobs:
|
|
|
34
34
|
name: Rust-accelerated (parity tests)
|
|
35
35
|
runs-on: ubuntu-latest
|
|
36
36
|
steps:
|
|
37
|
-
- uses: actions/checkout@
|
|
37
|
+
- uses: actions/checkout@v5
|
|
38
38
|
|
|
39
|
-
- uses: actions/setup-python@
|
|
39
|
+
- uses: actions/setup-python@v6
|
|
40
40
|
with:
|
|
41
41
|
python-version: "3.10"
|
|
42
42
|
|
|
@@ -18,6 +18,7 @@ __pycache__/
|
|
|
18
18
|
# Claude Code
|
|
19
19
|
.claude/
|
|
20
20
|
CLAUDE.md
|
|
21
|
+
HANDOFF.md
|
|
21
22
|
|
|
22
23
|
# Jupyter checkpoints
|
|
23
24
|
.ipynb_checkpoints/
|
|
@@ -36,9 +37,9 @@ target/
|
|
|
36
37
|
*.rtf
|
|
37
38
|
*.VFP
|
|
38
39
|
*.png
|
|
39
|
-
|
|
40
|
-
# Standalone ILT development (lives in ilt-inversion repo)
|
|
41
|
-
ilt/
|
|
42
|
-
benchmark_ilt.py
|
|
43
|
-
benchmark_rust.py
|
|
44
|
-
BUILD_INSTRUCTIONS.txt
|
|
40
|
+
|
|
41
|
+
# Standalone ILT development (lives in ilt-inversion repo)
|
|
42
|
+
ilt/
|
|
43
|
+
benchmark_ilt.py
|
|
44
|
+
benchmark_rust.py
|
|
45
|
+
BUILD_INSTRUCTIONS.txt
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# pyrestoolbox-mcp: deployment note for the Mawson platform team
|
|
2
|
+
|
|
3
|
+
## What this is
|
|
4
|
+
|
|
5
|
+
An MCP (Model Context Protocol) server exposing pyResToolbox, a petroleum
|
|
6
|
+
engineering calculation library (gas/oil/brine PVT, nodal analysis, decline
|
|
7
|
+
curve analysis, material balance). Source: https://github.com/mwburgoyne/pyResToolbox
|
|
8
|
+
(server code in `mcp/`). Contact: Mark Burgoyne.
|
|
9
|
+
|
|
10
|
+
It gives an LLM seven tools: three discovery/dispatch tools that reach the
|
|
11
|
+
library's full public API (about 125 functions), a correlation-method
|
|
12
|
+
recommender, and three one-shot calculation wrappers. Module documentation
|
|
13
|
+
with worked examples is served as MCP resources. Wrong inputs return errors
|
|
14
|
+
that list the valid options, so the model self-corrects without help.
|
|
15
|
+
|
|
16
|
+
## Security properties
|
|
17
|
+
|
|
18
|
+
- Pure computation. The server makes no outbound network calls, reads no
|
|
19
|
+
external data sources, and writes nothing to disk. Requests contain only
|
|
20
|
+
numeric/string calculation inputs; responses are JSON numbers and text.
|
|
21
|
+
- No credentials, no state, no user data. Nothing is retained between
|
|
22
|
+
requests.
|
|
23
|
+
- Licence: GPL-3.0. Internal use is not distribution, so no obligations are
|
|
24
|
+
triggered, and the source is public in any case.
|
|
25
|
+
|
|
26
|
+
## How to deploy
|
|
27
|
+
|
|
28
|
+
1. Build the container from the repo's `mcp/` directory (Dockerfile
|
|
29
|
+
included; pyresToolbox version is pinned via a build arg). No base-image
|
|
30
|
+
requirements beyond python:3.11-slim.
|
|
31
|
+
2. Run it anywhere inside the Santos network. It listens on port 8000 and
|
|
32
|
+
serves MCP streamable HTTP at `/mcp`. It is stateless: replicas can sit
|
|
33
|
+
behind a load balancer without session affinity.
|
|
34
|
+
3. Put your standard API gateway in front for authentication. The server
|
|
35
|
+
itself does not authenticate; it expects to live behind the gateway.
|
|
36
|
+
4. Register the endpoint URL with Mawson as a remote MCP server.
|
|
37
|
+
|
|
38
|
+
If Mawson does not support remote MCP servers and needs an OpenAPI tool
|
|
39
|
+
spec instead, tell us; the tool layer is plain typed Python and a REST
|
|
40
|
+
wrapper is straightforward.
|
|
41
|
+
|
|
42
|
+
## Sizing
|
|
43
|
+
|
|
44
|
+
Single-digit milliseconds to low seconds per calculation, CPU-bound, modest
|
|
45
|
+
memory (numpy/scipy stack, roughly 500 MB resident). One small container is
|
|
46
|
+
enough to start; scale horizontally if usage grows.
|
|
47
|
+
|
|
48
|
+
## Updates
|
|
49
|
+
|
|
50
|
+
Version bumps are deliberate: rebuild the image with a new
|
|
51
|
+
`PYRESTOOLBOX_VERSION` build arg after the library publishes a release.
|
|
52
|
+
The calculation library is regression-tested (900+ tests, frozen numerical
|
|
53
|
+
baselines, documentation examples verified in CI).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# pyrestoolbox-mcp: remote MCP server (streamable HTTP)
|
|
2
|
+
# Build from the mcp/ directory: docker build -t pyrestoolbox-mcp .
|
|
3
|
+
# Run: docker run -p 8000:8000 pyrestoolbox-mcp
|
|
4
|
+
# MCP endpoint: http://<host>:8000/mcp
|
|
5
|
+
|
|
6
|
+
FROM python:3.11-slim
|
|
7
|
+
|
|
8
|
+
# Pin the library version for reproducible corporate deployments; bump
|
|
9
|
+
# deliberately and rebuild.
|
|
10
|
+
ARG PYRESTOOLBOX_VERSION=3.7.0
|
|
11
|
+
|
|
12
|
+
WORKDIR /app
|
|
13
|
+
COPY . /app/mcp
|
|
14
|
+
|
|
15
|
+
RUN pip install --no-cache-dir "pyrestoolbox==${PYRESTOOLBOX_VERSION}" /app/mcp
|
|
16
|
+
|
|
17
|
+
# Non-root runtime user
|
|
18
|
+
RUN useradd --create-home --shell /usr/sbin/nologin mcp
|
|
19
|
+
USER mcp
|
|
20
|
+
|
|
21
|
+
EXPOSE 8000
|
|
22
|
+
|
|
23
|
+
CMD ["pyrestoolbox-mcp", "--transport", "streamable-http", "--host", "0.0.0.0", "--port", "8000"]
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# pyrestoolbox-mcp
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server exposing the
|
|
4
|
+
[pyrestoolbox](https://github.com/mwburgoyne/pyResToolbox) reservoir
|
|
5
|
+
engineering library to agents without a Python execution environment
|
|
6
|
+
(Claude Desktop, claude.ai connectors, other MCP hosts).
|
|
7
|
+
|
|
8
|
+
If your agent CAN run Python, prefer `pip install pyrestoolbox` directly -
|
|
9
|
+
the library ships its full documentation inside the wheel
|
|
10
|
+
(`pyrestoolbox.docs_dir()`), and native code execution is more flexible than
|
|
11
|
+
any tool surface.
|
|
12
|
+
|
|
13
|
+
## Design
|
|
14
|
+
|
|
15
|
+
A small meta-tool surface instead of one MCP tool per library function:
|
|
16
|
+
|
|
17
|
+
| Tool | Purpose |
|
|
18
|
+
|---|---|
|
|
19
|
+
| `list_functions(module?)` | Module map, or public functions of one module |
|
|
20
|
+
| `describe(name)` | Signature + docstring for `module.function` |
|
|
21
|
+
| `call(name, arguments)` | Invoke any public function with keyword args |
|
|
22
|
+
| `recommend_methods(...)` | Correlation-method recommendations with rationale |
|
|
23
|
+
| `co2_brine_props(...)` | One-shot CO2-saturated brine properties |
|
|
24
|
+
| `sw_brine_props(...)` | One-shot multicomponent gas-saturated brine properties |
|
|
25
|
+
| `fit_and_forecast(...)` | Fit a decline model and forecast in one call |
|
|
26
|
+
|
|
27
|
+
Every module's RST documentation (shipped in the pyrestoolbox wheel) is
|
|
28
|
+
exposed as an MCP resource: `docs://gas`, `docs://oil`, `docs://index`, ...
|
|
29
|
+
|
|
30
|
+
Correlation methods are passed as strings (`"zmethod": "DAK"`); an invalid
|
|
31
|
+
method string returns an error listing the valid options, so agents
|
|
32
|
+
self-correct in one round trip. Results are JSON: numpy arrays become lists,
|
|
33
|
+
DataFrames become `{columns, records}`, non-finite floats become null.
|
|
34
|
+
|
|
35
|
+
## Install and configure
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
pip install pyrestoolbox-mcp # once published; or: pip install ./mcp
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Claude Code:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
claude mcp add pyrestoolbox -- pyrestoolbox-mcp
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Claude Desktop (`claude_desktop_config.json`):
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"mcpServers": {
|
|
52
|
+
"pyrestoolbox": {
|
|
53
|
+
"command": "pyrestoolbox-mcp"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Remote deployment (enterprise LLM platforms)
|
|
60
|
+
|
|
61
|
+
The server also runs as a remote MCP server over streamable HTTP:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
pyrestoolbox-mcp --transport streamable-http --host 0.0.0.0 --port 8000
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
It is stateless (no session affinity needed behind a load balancer) and
|
|
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.
|
|
71
|
+
|
|
72
|
+
## Tests
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
PYTHONPATH=<repo>:<repo>/mcp python3 -m pytest mcp/tests/ -q
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Notes
|
|
79
|
+
|
|
80
|
+
- Units default to oilfield (psia, deg F, ft, mD, cP); pass `metric: true`
|
|
81
|
+
where the function supports it. The plyasunov module is SI (K, MPa).
|
|
82
|
+
- 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.
|
|
86
|
+
- File-writing simtools functions keep their `export=False` defaults, so
|
|
87
|
+
calls return table text rather than touching disk.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "pyrestoolbox-mcp"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "MCP server exposing the pyrestoolbox reservoir engineering library"
|
|
9
|
+
license = {text = "GPL-3.0-or-later"}
|
|
10
|
+
authors = [{name = "Mark W. Burgoyne", email = "mark.w.burgoyne@gmail.com"}]
|
|
11
|
+
keywords = ["mcp", "petroleum", "reservoir", "pyrestoolbox"]
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
dependencies = [
|
|
14
|
+
"mcp>=1.2",
|
|
15
|
+
"pyrestoolbox>=3.7",
|
|
16
|
+
]
|
|
17
|
+
readme = "README.md"
|
|
18
|
+
|
|
19
|
+
[project.urls]
|
|
20
|
+
Homepage = "https://github.com/mwburgoyne/pyResToolbox"
|
|
21
|
+
|
|
22
|
+
[project.scripts]
|
|
23
|
+
pyrestoolbox-mcp = "pyrestoolbox_mcp.server:main"
|
|
24
|
+
|
|
25
|
+
[tool.setuptools.packages.find]
|
|
26
|
+
include = ["pyrestoolbox_mcp*"]
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""Convert pyrestoolbox return values to JSON-serializable structures."""
|
|
2
|
+
|
|
3
|
+
import dataclasses
|
|
4
|
+
import math
|
|
5
|
+
from enum import Enum
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def to_jsonable(obj):
|
|
9
|
+
"""Recursively convert obj to JSON-serializable Python primitives.
|
|
10
|
+
|
|
11
|
+
numpy scalars/arrays, pandas DataFrames/Series, dataclasses, Enums and
|
|
12
|
+
nested containers are handled. Non-finite floats become None (JSON has
|
|
13
|
+
no NaN/inf).
|
|
14
|
+
"""
|
|
15
|
+
if obj is None or isinstance(obj, (bool, str)):
|
|
16
|
+
return obj
|
|
17
|
+
if isinstance(obj, int):
|
|
18
|
+
return int(obj)
|
|
19
|
+
if isinstance(obj, float): # np.float64 subclasses float - cast to plain float
|
|
20
|
+
return float(obj) if math.isfinite(obj) else None
|
|
21
|
+
if isinstance(obj, Enum):
|
|
22
|
+
return obj.name
|
|
23
|
+
if dataclasses.is_dataclass(obj) and not isinstance(obj, type):
|
|
24
|
+
return {f.name: to_jsonable(getattr(obj, f.name)) for f in dataclasses.fields(obj)}
|
|
25
|
+
# numpy
|
|
26
|
+
try:
|
|
27
|
+
import numpy as np
|
|
28
|
+
if isinstance(obj, np.generic):
|
|
29
|
+
return to_jsonable(obj.item())
|
|
30
|
+
if isinstance(obj, np.ndarray):
|
|
31
|
+
return [to_jsonable(v) for v in obj.tolist()]
|
|
32
|
+
except ImportError:
|
|
33
|
+
pass
|
|
34
|
+
# pandas
|
|
35
|
+
try:
|
|
36
|
+
import pandas as pd
|
|
37
|
+
if isinstance(obj, pd.DataFrame):
|
|
38
|
+
return {
|
|
39
|
+
"columns": [str(c) for c in obj.columns],
|
|
40
|
+
"records": to_jsonable(obj.to_dict(orient="records")),
|
|
41
|
+
}
|
|
42
|
+
if isinstance(obj, pd.Series):
|
|
43
|
+
return to_jsonable(obj.tolist())
|
|
44
|
+
except ImportError:
|
|
45
|
+
pass
|
|
46
|
+
if isinstance(obj, dict):
|
|
47
|
+
return {str(k): to_jsonable(v) for k, v in obj.items()}
|
|
48
|
+
if isinstance(obj, (list, tuple, set)):
|
|
49
|
+
return [to_jsonable(v) for v in obj]
|
|
50
|
+
return str(obj)
|