gnnepcsaft-mcp-server 0.3.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.
- gnnepcsaft_mcp_server-0.3.1/PKG-INFO +59 -0
- gnnepcsaft_mcp_server-0.3.1/README.md +34 -0
- gnnepcsaft_mcp_server-0.3.1/gnnepcsaft_mcp_server/__init__.py +1 -0
- gnnepcsaft_mcp_server-0.3.1/gnnepcsaft_mcp_server/mcp_server.py +51 -0
- gnnepcsaft_mcp_server-0.3.1/gnnepcsaft_mcp_server/models/.gitignore +0 -0
- gnnepcsaft_mcp_server-0.3.1/gnnepcsaft_mcp_server/models/assoc_8.onnx +0 -0
- gnnepcsaft_mcp_server-0.3.1/gnnepcsaft_mcp_server/models/msigmae_7.onnx +0 -0
- gnnepcsaft_mcp_server-0.3.1/gnnepcsaft_mcp_server/plot_utils.py +28 -0
- gnnepcsaft_mcp_server-0.3.1/gnnepcsaft_mcp_server/utils.py +330 -0
- gnnepcsaft_mcp_server-0.3.1/pyproject.toml +34 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gnnepcsaft-mcp-server
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: Model Context Protocol server for GNNePCSAFT tools
|
|
5
|
+
License: GNU General Public License v3.0
|
|
6
|
+
Author: wildsonbbl
|
|
7
|
+
Author-email: wil_bbl@hotmail.com
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Classifier: License :: Other/Proprietary License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Requires-Dist: feos (>=0.8.0,<0.9.0)
|
|
17
|
+
Requires-Dist: gnnepcsaft (>=0.2.4)
|
|
18
|
+
Requires-Dist: mcp (>=1.6.0,<2.0.0)
|
|
19
|
+
Requires-Dist: numpy (>=2.2.4,<3.0.0)
|
|
20
|
+
Requires-Dist: onnxruntime (>=1.21.0,<2.0.0)
|
|
21
|
+
Requires-Dist: rdkit (>=2024.9.6,<2025.0.0)
|
|
22
|
+
Requires-Dist: si-units (>=0.11.0,<0.12.0)
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# GNNEPCSAFT MCP Server
|
|
26
|
+
|
|
27
|
+
GNNEPCSAFT MCP Server is an implementation of the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) for [GNNePCSAFT](https://github.com/wildsonbbl/gnnepcsaft) tools. GNNePCSAFT leverages Graph Neural Networks (GNNs) to estimate [PC-SAFT](https://en.wikipedia.org/wiki/PC-SAFT) pure-component parameters, allowing property predictions such as density and vapor pressure for any molecule or mixture. [FeOs](https://github.com/feos-org/feos) is used for PC-SAFT calculations.
|
|
28
|
+
|
|
29
|
+
## How to Use
|
|
30
|
+
|
|
31
|
+
### Installation
|
|
32
|
+
|
|
33
|
+
You need [uvx](https://docs.astral.sh/uv/) installed.
|
|
34
|
+
|
|
35
|
+
### Starting the Server
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
uvx --from gnnepcsaft-mcp-server gnnepcsaftmcp
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Example: Claude Desktop Configuration
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"mcpServers": {
|
|
46
|
+
"gnnepcsaft": {
|
|
47
|
+
"command": "uvx",
|
|
48
|
+
"args": ["--from", "gnnepcsaft-mcp-server", "gnnepcsaftmcp"]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## License
|
|
57
|
+
|
|
58
|
+
GNU General Public License v3.0
|
|
59
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# GNNEPCSAFT MCP Server
|
|
2
|
+
|
|
3
|
+
GNNEPCSAFT MCP Server is an implementation of the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) for [GNNePCSAFT](https://github.com/wildsonbbl/gnnepcsaft) tools. GNNePCSAFT leverages Graph Neural Networks (GNNs) to estimate [PC-SAFT](https://en.wikipedia.org/wiki/PC-SAFT) pure-component parameters, allowing property predictions such as density and vapor pressure for any molecule or mixture. [FeOs](https://github.com/feos-org/feos) is used for PC-SAFT calculations.
|
|
4
|
+
|
|
5
|
+
## How to Use
|
|
6
|
+
|
|
7
|
+
### Installation
|
|
8
|
+
|
|
9
|
+
You need [uvx](https://docs.astral.sh/uv/) installed.
|
|
10
|
+
|
|
11
|
+
### Starting the Server
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
uvx --from gnnepcsaft-mcp-server gnnepcsaftmcp
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Example: Claude Desktop Configuration
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"mcpServers": {
|
|
22
|
+
"gnnepcsaft": {
|
|
23
|
+
"command": "uvx",
|
|
24
|
+
"args": ["--from", "gnnepcsaft-mcp-server", "gnnepcsaftmcp"]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## License
|
|
33
|
+
|
|
34
|
+
GNU General Public License v3.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"GNNePCSAFT MCP Server"
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"GNNePCSAFT MCP Server"
|
|
2
|
+
|
|
3
|
+
from typing import Any, Callable, List
|
|
4
|
+
|
|
5
|
+
from mcp.server.fastmcp import FastMCP
|
|
6
|
+
|
|
7
|
+
from .plot_utils import v3000_mol_block
|
|
8
|
+
from .utils import (
|
|
9
|
+
batch_convert_pure_density_to_kg_per_m3,
|
|
10
|
+
batch_critical_points,
|
|
11
|
+
batch_inchi_to_smiles,
|
|
12
|
+
batch_molecular_weights,
|
|
13
|
+
batch_pa_to_bar,
|
|
14
|
+
batch_predict_epcsaft_parameters,
|
|
15
|
+
batch_pure_density,
|
|
16
|
+
batch_pure_h_lv,
|
|
17
|
+
batch_pure_vapor_pressure,
|
|
18
|
+
batch_smiles_to_inchi,
|
|
19
|
+
mixture_density,
|
|
20
|
+
mixture_phase,
|
|
21
|
+
mixture_vapor_pressure,
|
|
22
|
+
pubchem_description,
|
|
23
|
+
pure_phase,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
mcp = FastMCP("gnnepcsaft")
|
|
27
|
+
fn_list: List[Callable[..., Any]] = [
|
|
28
|
+
batch_convert_pure_density_to_kg_per_m3,
|
|
29
|
+
batch_critical_points,
|
|
30
|
+
batch_inchi_to_smiles,
|
|
31
|
+
batch_molecular_weights,
|
|
32
|
+
batch_pa_to_bar,
|
|
33
|
+
batch_predict_epcsaft_parameters,
|
|
34
|
+
batch_pure_density,
|
|
35
|
+
batch_pure_h_lv,
|
|
36
|
+
batch_pure_vapor_pressure,
|
|
37
|
+
batch_smiles_to_inchi,
|
|
38
|
+
mixture_density,
|
|
39
|
+
mixture_phase,
|
|
40
|
+
mixture_vapor_pressure,
|
|
41
|
+
pubchem_description,
|
|
42
|
+
pure_phase,
|
|
43
|
+
v3000_mol_block,
|
|
44
|
+
]
|
|
45
|
+
for fn in fn_list:
|
|
46
|
+
mcp.add_tool(fn)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def run():
|
|
50
|
+
"run stdio"
|
|
51
|
+
mcp.run("stdio")
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"plot utils"
|
|
2
|
+
|
|
3
|
+
from rdkit.Chem import AllChem as Chem
|
|
4
|
+
|
|
5
|
+
from .utils import smilestoinchi
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def v3000_mol_block(smiles: str) -> str:
|
|
9
|
+
"""Returns a V3000 Mol block for a molecule.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
smiles (str): SMILES of the molecule.
|
|
13
|
+
|
|
14
|
+
"""
|
|
15
|
+
inchi = smilestoinchi(smiles)
|
|
16
|
+
|
|
17
|
+
mol = Chem.MolFromInchi(inchi)
|
|
18
|
+
mol = Chem.AddHs(mol) # type: ignore
|
|
19
|
+
params = Chem.ETKDGv3() # type: ignore
|
|
20
|
+
params.randomSeed = 0xF00D
|
|
21
|
+
result = Chem.EmbedMolecule(mol, params) # type: ignore
|
|
22
|
+
if result == 0:
|
|
23
|
+
Chem.MMFFOptimizeMolecule( # type: ignore
|
|
24
|
+
mol, maxIters=1000, nonBondedThresh=100, ignoreInterfragInteractions=False
|
|
25
|
+
)
|
|
26
|
+
# mol = Chem.RemoveHs(mol, implicitOnly=False)
|
|
27
|
+
imgmol = Chem.MolToV3KMolBlock(mol) # type: ignore
|
|
28
|
+
return imgmol
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
"Utils for MCP Server"
|
|
2
|
+
|
|
3
|
+
from json import loads
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import List, Literal, Tuple
|
|
6
|
+
from urllib.parse import quote
|
|
7
|
+
from urllib.request import HTTPError, urlopen
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
import onnxruntime as ort
|
|
11
|
+
from gnnepcsaft.data.ogb_utils import smiles2graph
|
|
12
|
+
from gnnepcsaft.data.rdkit_util import assoc_number, inchitosmiles, mw, smilestoinchi
|
|
13
|
+
from gnnepcsaft.epcsaft.epcsaft_feos import (
|
|
14
|
+
critical_points_feos,
|
|
15
|
+
mix_den_feos,
|
|
16
|
+
mix_vp_feos,
|
|
17
|
+
pure_den_feos,
|
|
18
|
+
pure_h_lv_feos,
|
|
19
|
+
pure_vp_feos,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
file_dir = Path(__file__).parent
|
|
23
|
+
model_dir = file_dir / "models"
|
|
24
|
+
ort.set_default_logger_severity(3)
|
|
25
|
+
|
|
26
|
+
msigmae_onnx = ort.InferenceSession(model_dir / "msigmae_7.onnx")
|
|
27
|
+
assoc_onnx = ort.InferenceSession(model_dir / "assoc_8.onnx")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def predict_epcsaft_parameters(
|
|
31
|
+
smiles: str,
|
|
32
|
+
) -> List[float]:
|
|
33
|
+
"""Predict PC-SAFT parameters
|
|
34
|
+
`[m, sigma, epsilon/kB, kappa_ab, epsilon_ab/kB, dipole moment, na, nb, MW]` with
|
|
35
|
+
the GNNePCSAFT model.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
smiles (str): SMILES of the molecule.
|
|
39
|
+
"""
|
|
40
|
+
lower_bounds = np.asarray([1.0, 1.9, 50.0, 0.0, 0.0, 0, 0, 0, 0])
|
|
41
|
+
upper_bounds = np.asarray(
|
|
42
|
+
[25.0, 4.5, 550.0, 0.9, 5000.0, np.inf, np.inf, np.inf, np.inf]
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
inchi = smilestoinchi(smiles)
|
|
46
|
+
|
|
47
|
+
graph = smiles2graph(smiles)
|
|
48
|
+
na, nb = assoc_number(inchi)
|
|
49
|
+
x, edge_index, edge_attr = (
|
|
50
|
+
graph["node_feat"],
|
|
51
|
+
graph["edge_index"],
|
|
52
|
+
graph["edge_feat"],
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
assoc = 10 ** (
|
|
56
|
+
assoc_onnx.run(
|
|
57
|
+
None,
|
|
58
|
+
{
|
|
59
|
+
"x": x,
|
|
60
|
+
"edge_index": edge_index,
|
|
61
|
+
"edge_attr": edge_attr,
|
|
62
|
+
},
|
|
63
|
+
)[0][0]
|
|
64
|
+
* np.asarray([-1.0, 1.0])
|
|
65
|
+
)
|
|
66
|
+
if na == 0 and nb == 0:
|
|
67
|
+
assoc *= 0
|
|
68
|
+
msigmae = msigmae_onnx.run(
|
|
69
|
+
None,
|
|
70
|
+
{
|
|
71
|
+
"x": x,
|
|
72
|
+
"edge_index": edge_index,
|
|
73
|
+
"edge_attr": edge_attr,
|
|
74
|
+
},
|
|
75
|
+
)[0][0]
|
|
76
|
+
munanbmw = np.asarray([0.0, na, nb, mw(inchi)])
|
|
77
|
+
pred = np.hstack([msigmae, assoc, munanbmw], dtype=np.float64)
|
|
78
|
+
np.clip(pred, lower_bounds, upper_bounds, out=pred)
|
|
79
|
+
|
|
80
|
+
return pred.tolist() # type: ignore
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def pure_phase(
|
|
84
|
+
vapor_pressure: float, system_pressure: float
|
|
85
|
+
) -> Literal["liquid", "vapor"]:
|
|
86
|
+
"""
|
|
87
|
+
Given the vapor pressure and system pressure, return the phase of the molecule.
|
|
88
|
+
Both pressures must be in the same unit.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
vapor_pressure (float): The calculated vapor pressure of the pure component.
|
|
92
|
+
system_pressure (float): The actual system pressure.
|
|
93
|
+
|
|
94
|
+
"""
|
|
95
|
+
assert isinstance(vapor_pressure, (int, float)), "vapor_pressure must be a number"
|
|
96
|
+
assert isinstance(system_pressure, (int, float)), "system_pressure must be a number"
|
|
97
|
+
assert vapor_pressure > 0, "vapor_pressure must be positive"
|
|
98
|
+
assert system_pressure > 0, "system_pressure must be positive"
|
|
99
|
+
|
|
100
|
+
return "liquid" if vapor_pressure < system_pressure else "vapor"
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def mixture_phase(
|
|
104
|
+
bubble_point: float,
|
|
105
|
+
dew_point: float,
|
|
106
|
+
system_pressure: float,
|
|
107
|
+
) -> Literal["liquid", "vapor", "two-phase"]:
|
|
108
|
+
"""
|
|
109
|
+
Given the bubble/dew point of the mixture and the system pressure,
|
|
110
|
+
return the phase of the mixture.
|
|
111
|
+
All pressures must be in the same unit.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
bubble_point (float): The calculated bubble point of the mixture.
|
|
115
|
+
dew_point (float): The calculated dew point of the mixture.
|
|
116
|
+
system_pressure (float): The actual system pressure.
|
|
117
|
+
"""
|
|
118
|
+
assert isinstance(bubble_point, (int, float)), "bubble_point must be a number"
|
|
119
|
+
assert isinstance(dew_point, (int, float)), "dew_point must be a number"
|
|
120
|
+
assert isinstance(system_pressure, (int, float)), "system_pressure must be a number"
|
|
121
|
+
assert bubble_point > 0, "bubble_point must be positive"
|
|
122
|
+
assert dew_point > 0, "dew_point must be positive"
|
|
123
|
+
assert system_pressure > 0, "system_pressure must be positive"
|
|
124
|
+
return (
|
|
125
|
+
"liquid"
|
|
126
|
+
if bubble_point < system_pressure
|
|
127
|
+
else ("two-phase" if dew_point <= system_pressure else "vapor")
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def pubchem_description(smiles: str) -> str:
|
|
132
|
+
"""
|
|
133
|
+
Look for information on PubChem for the SMILES.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
smiles (str): The SMILES of the molecule.
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
try:
|
|
140
|
+
inchi = smilestoinchi(smiles)
|
|
141
|
+
url = (
|
|
142
|
+
"https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/inchi/description/json?inchi="
|
|
143
|
+
+ quote(inchi, safe="")
|
|
144
|
+
)
|
|
145
|
+
with urlopen(url) as ans:
|
|
146
|
+
ans = loads(ans.read().decode("utf8").strip())
|
|
147
|
+
except (TypeError, HTTPError, ValueError):
|
|
148
|
+
ans = "no data available on this molecule in PubChem."
|
|
149
|
+
return ans
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def mixture_density(
|
|
153
|
+
parameters: List[List[float]],
|
|
154
|
+
state: List[float],
|
|
155
|
+
kij_matrix: List[List[float]],
|
|
156
|
+
) -> float:
|
|
157
|
+
"""Calculates mixture liquid density (mol/m³) with PC-SAFT.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
parameters: A list of
|
|
161
|
+
`[m, sigma, epsilon/kB, kappa_ab, epsilon_ab/kB, dipole moment, na, nb, MW]`
|
|
162
|
+
for each component of the mixture
|
|
163
|
+
state: A list with the state of the mixture
|
|
164
|
+
`[Temperature (K), Pressure (Pa), mole_fractions_1, mole_fractions_2, ...]`
|
|
165
|
+
kij_matrix: A matrix of binary interaction parameters
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
return mix_den_feos(parameters, state, kij_matrix)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def mixture_vapor_pressure(
|
|
172
|
+
parameters: List[List[float]],
|
|
173
|
+
state: List[float],
|
|
174
|
+
kij_matrix: List[List[float]],
|
|
175
|
+
) -> Tuple[float, float]:
|
|
176
|
+
"""Calculates mixture `(Bubble point (Pa), Dew point (Pa))` with PC-SAFT.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
parameters: A list of
|
|
180
|
+
`[m, sigma, epsilon/kB, kappa_ab, epsilon_ab/kB, dipole moment, na, nb, MW]`
|
|
181
|
+
for each component of the mixture
|
|
182
|
+
state: A list with the state of the mixture
|
|
183
|
+
`[Temperature (K), Pressure (Pa), mole_fractions_1, molefractions_2, ...]`.
|
|
184
|
+
The pressure should be any `float` value since it's not used in the calculation.
|
|
185
|
+
kij_matrix: A matrix of binary interaction parameters.
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
return mix_vp_feos(parameters, state, kij_matrix)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def batch_predict_epcsaft_parameters(
|
|
192
|
+
smiles: List[str],
|
|
193
|
+
) -> List[List[float]]:
|
|
194
|
+
"""Predict PC-SAFT parameters
|
|
195
|
+
`[m, sigma, epsilon/kB, kappa_ab, epsilon_ab/kB, dipole moment, na, nb, MW]`
|
|
196
|
+
for a list of SMILES with the GNNePCSAFT model.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
smiles (List[str]): SMILES of the molecules.
|
|
200
|
+
"""
|
|
201
|
+
return [predict_epcsaft_parameters(smi) for smi in smiles]
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def batch_molecular_weights(
|
|
205
|
+
smiles: List[str],
|
|
206
|
+
) -> List[float]:
|
|
207
|
+
"""Calcultes molecular weight in `g/mol` for a list of SMILES
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
smiles (List[str]): SMILES of the molecules.
|
|
211
|
+
"""
|
|
212
|
+
inchi_list = [smilestoinchi(smi) for smi in smiles]
|
|
213
|
+
return [mw(inchi) for inchi in inchi_list]
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def batch_inchi_to_smiles(
|
|
217
|
+
inchi_list: List[str],
|
|
218
|
+
) -> List[str]:
|
|
219
|
+
"""Transform a list of InChI to SMILES.
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
inchi_list (List[str]): List of InChI
|
|
223
|
+
"""
|
|
224
|
+
return [inchitosmiles(inchi) for inchi in inchi_list]
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def batch_smiles_to_inchi(
|
|
228
|
+
smiles_list: List[str],
|
|
229
|
+
) -> List[str]:
|
|
230
|
+
"""Transform a list of SMILES to InChI.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
smiles_list (List[str]): List of SMILES
|
|
234
|
+
"""
|
|
235
|
+
return [smilestoinchi(smi) for smi in smiles_list]
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def batch_pure_density(
|
|
239
|
+
smiles_list: List[str],
|
|
240
|
+
state: List[float],
|
|
241
|
+
) -> List[float]:
|
|
242
|
+
"""Calculates pure liquid density in `mol/m³` with PC-SAFT for a list of SMILES.
|
|
243
|
+
The state is the same for all molecules. The GNNePCSAFT model is used to predict
|
|
244
|
+
PCSAFT parameters.
|
|
245
|
+
|
|
246
|
+
Args:
|
|
247
|
+
smiles_list (List[str]): List of SMILES
|
|
248
|
+
state: A list with
|
|
249
|
+
`[Temperature (K), Pressure (Pa)]`
|
|
250
|
+
"""
|
|
251
|
+
return [
|
|
252
|
+
pure_den_feos(predict_epcsaft_parameters(smi), state) for smi in smiles_list
|
|
253
|
+
]
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def batch_pure_vapor_pressure(
|
|
257
|
+
smiles_list: List[str],
|
|
258
|
+
temperature: float,
|
|
259
|
+
) -> List[float]:
|
|
260
|
+
"""Calculates pure vapor pressure in `Pa` with PC-SAFT for a list of SMILES.
|
|
261
|
+
The temperature is the same for all molecules. The GNNePCSAFT model is used to predict
|
|
262
|
+
PCSAFT parameters.
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
smiles_list (List[str]): List of SMILES
|
|
266
|
+
temperature: `Temperature (K)`
|
|
267
|
+
"""
|
|
268
|
+
return [
|
|
269
|
+
pure_vp_feos(predict_epcsaft_parameters(smi), [temperature])
|
|
270
|
+
for smi in smiles_list
|
|
271
|
+
]
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def batch_pure_h_lv(
|
|
275
|
+
smiles_list: List[str],
|
|
276
|
+
temperature: float,
|
|
277
|
+
) -> List[float]:
|
|
278
|
+
"""Calculates pure liquid enthalpy of vaporization in `kJ/mol`
|
|
279
|
+
with PC-SAFT for a list of SMILES.
|
|
280
|
+
The temperature is the same for all molecules.
|
|
281
|
+
The GNNePCSAFT model is used to predict
|
|
282
|
+
PCSAFT parameters.
|
|
283
|
+
|
|
284
|
+
Args:
|
|
285
|
+
smiles_list (List[str]): List of SMILES
|
|
286
|
+
temperature: `Temperature (K)`
|
|
287
|
+
"""
|
|
288
|
+
return [
|
|
289
|
+
pure_h_lv_feos(predict_epcsaft_parameters(smi), [temperature])
|
|
290
|
+
for smi in smiles_list
|
|
291
|
+
]
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def batch_critical_points(
|
|
295
|
+
smiles_list: List[str],
|
|
296
|
+
) -> List[List[float]]:
|
|
297
|
+
"""
|
|
298
|
+
Calculates critical points `[Temperature (K), Pressure (Pa), Density (mol/m³)]` with PC-SAFT
|
|
299
|
+
for a list of SMILES. The GNNePCSAFT model is used to predict PCSAFT parameters.
|
|
300
|
+
|
|
301
|
+
Args:
|
|
302
|
+
smiles_list (List[str]): List of SMILES
|
|
303
|
+
"""
|
|
304
|
+
return [
|
|
305
|
+
critical_points_feos(predict_epcsaft_parameters(smi)) for smi in smiles_list
|
|
306
|
+
]
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def batch_pa_to_bar(
|
|
310
|
+
pressure_in_pa_list: List[float],
|
|
311
|
+
) -> List[float]:
|
|
312
|
+
"""Convert a list of pressure from `Pa` to `bar`.
|
|
313
|
+
|
|
314
|
+
Args:
|
|
315
|
+
pressure_in_pa_list (List[float]): List of pressure in `Pa`
|
|
316
|
+
"""
|
|
317
|
+
return [pa / 100_000.0 for pa in pressure_in_pa_list]
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def batch_convert_pure_density_to_kg_per_m3(
|
|
321
|
+
density_list: List[float],
|
|
322
|
+
molecular_weight_list: List[float],
|
|
323
|
+
) -> List[float]:
|
|
324
|
+
"""Convert a list of density from `mol/m³` to `kg/m³`
|
|
325
|
+
|
|
326
|
+
Args:
|
|
327
|
+
density_list (List[float]): List of density in `mol/m³`
|
|
328
|
+
molecular_weight_list (List[float]): List of molecular weight in `g/mol`
|
|
329
|
+
"""
|
|
330
|
+
return [den * molw / 1000 for den, molw in zip(density_list, molecular_weight_list)]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "gnnepcsaft-mcp-server"
|
|
3
|
+
version = "0.3.1"
|
|
4
|
+
description = "Model Context Protocol server for GNNePCSAFT tools"
|
|
5
|
+
authors = [
|
|
6
|
+
{name = "wildsonbbl",email = "wil_bbl@hotmail.com"}
|
|
7
|
+
]
|
|
8
|
+
license = {text = "GNU General Public License v3.0"}
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"numpy (>=2.2.4,<3.0.0)",
|
|
13
|
+
"onnxruntime (>=1.21.0,<2.0.0)",
|
|
14
|
+
"gnnepcsaft (>=0.2.4)",
|
|
15
|
+
"mcp (>=1.6.0,<2.0.0)",
|
|
16
|
+
"rdkit (>=2024.9.6,<2025.0.0)",
|
|
17
|
+
"feos (>=0.8.0,<0.9.0)",
|
|
18
|
+
"si-units (>=0.11.0,<0.12.0)",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
[project.scripts]
|
|
22
|
+
gnnepcsaftmcp = 'gnnepcsaft_mcp_server.mcp_server:run'
|
|
23
|
+
|
|
24
|
+
[tool.poetry]
|
|
25
|
+
include = ["gnnepcsaft_mcp_server/models/assoc_8.onnx", "gnnepcsaft_mcp_server/models/msigmae_7.onnx"]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
[tool.poetry.group.dev.dependencies]
|
|
30
|
+
pytest = "^8.3.5"
|
|
31
|
+
|
|
32
|
+
[build-system]
|
|
33
|
+
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
34
|
+
build-backend = "poetry.core.masonry.api"
|