permeability 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,6 @@
1
+ def main():
2
+ print("Hello from permeability!")
3
+
4
+
5
+ if __name__ == "__main__":
6
+ main()
@@ -0,0 +1,14 @@
1
+ from typing import Any
2
+
3
+
4
+ # Process result for calculation
5
+ def process_mcp_calculation_result(
6
+ value: Any,
7
+ unit: str,
8
+ meaning: str,
9
+ ) -> dict:
10
+ return {
11
+ "val": value,
12
+ "unit": unit,
13
+ "meaning": meaning,
14
+ }
@@ -0,0 +1,59 @@
1
+ # Instructions
2
+ mcp_instruction = """
3
+ Provide tools for scientific calculations related to Material Science.
4
+ """
5
+ permeability_calculation_instruction = """
6
+ Calculate permeability using the seepage distance method.
7
+ K = L² · μ · φ / (2 · t · ΔP)
8
+ If you fill the p_c field that is optional to fill, you will get the result corrected by the capillary pressure:
9
+ K = μ · φ · L² / (2 · t · (ΔP + p_c))
10
+ """
11
+ infiltration_time_calculation_instruction = """
12
+ Calculate total time for fluid to fully penetrate the sample.
13
+ t = μ · φ · L² / (2 · K · ΔP)
14
+ If you fill the p_c field that is optional to fill, you will get the result corrected by the capillary pressure:
15
+ t = μ · φ · L² / (2 · K · (ΔP + p_c))
16
+ """
17
+ m22darcy_instruction = """
18
+ Convert m^2 to Darcy
19
+ """
20
+ darcy2m2_instruction = """
21
+ Convert Darcy to m^2
22
+ """
23
+ infiltration_front_position_instruction = """
24
+ Calculate infiltration front position at given time(s).
25
+ z(t) = sqrt(2 · K · ΔP · t / (μ · φ))
26
+ If you fill the p_c field that is optional to fill, you will get the result corrected by the capillary pressure:
27
+ z(t) = sqrt(2 · K · (ΔP + p_c) · t / (μ · φ))
28
+ """
29
+ infiltration_front_position_multiple_time_instruction = """
30
+ Calculate infiltration front position at multiple times (for graph making).
31
+ z(t) = sqrt(2 · K · ΔP · t / (μ · φ))
32
+ If you fill the p_c field that is optional to fill, you will get the result corrected by the capillary pressure:
33
+ z(t) = sqrt(2 · K · (ΔP + p_c) · t / (μ · φ))
34
+ """
35
+ capillary_pressure_calculation_instruction = """
36
+ Calculate capillary pressure using the Young-Laplace equation.
37
+ pc = 2 · γ · cos(θ) / r
38
+ """
39
+ pressure_difference_calculation_instruction = """
40
+ Calculate pressure difference using the seepage distance method.
41
+ ΔP = μ · φ · L² / (2 · K · t)
42
+ If you fill the p_c field that is optional to fill, you will get the result corrected by the capillary pressure:
43
+ ΔP = μ · φ · L² / (2 · K · t) - p_c
44
+ """
45
+ # Seepage Distance Calculation
46
+ L_meaning = "Sample length/thickness along flow direction (m)"
47
+ mu_meaning = "Dynamic viscosity of the fluid (Pa·s)"
48
+ phi_meaning = "Porosity of the porous medium (dimensionless, 0 < phi <= 1)"
49
+ t_meaning = "Total time for fluid to fully penetrate the sample (s)"
50
+ multi_t_meaning = "Total time recorded for multiple rounds for fluid to fully penetrate the sample (s)"
51
+ dP_meaning = "Constant pressure difference across the sample (Pa)"
52
+ K_meaning = "Permeability (m²)"
53
+ m2K_meaning = "Permeability in m^2"
54
+ darcyK_meaning = "Permeability in Darcy"
55
+ z_meaning = "Infiltration front position at given time(s)"
56
+ p_c_meaning = "Capillary pressure (Pa)"
57
+ theta_meaning = "Contact angle (wetting angle) (Degrees)"
58
+ gamma_meaning = "Surface tension of the liquid (N/m)"
59
+ r_meaning = "Equivalent pore radius (m)"
@@ -0,0 +1,343 @@
1
+ from typing import (
2
+ Annotated,
3
+ List,
4
+ Optional
5
+ )
6
+ import argparse
7
+ import numpy as np
8
+ # Fastmcp dependencies
9
+ from fastmcp import FastMCP
10
+ from fastmcp.exceptions import ToolError
11
+ # Project dependencies
12
+ from permeability.mcp.ProcessResult import (
13
+ process_mcp_calculation_result
14
+ )
15
+ from permeability.mcp.Prompts import (
16
+ mcp_instruction,
17
+ permeability_calculation_instruction,
18
+ infiltration_time_calculation_instruction,
19
+ darcy2m2_instruction,
20
+ m22darcy_instruction,
21
+ infiltration_front_position_instruction,
22
+ infiltration_front_position_multiple_time_instruction,
23
+ capillary_pressure_calculation_instruction,
24
+ pressure_difference_calculation_instruction,
25
+ L_meaning,
26
+ mu_meaning,
27
+ phi_meaning,
28
+ t_meaning,
29
+ dP_meaning,
30
+ K_meaning,
31
+ multi_t_meaning,
32
+ darcyK_meaning,
33
+ m2K_meaning,
34
+ z_meaning,
35
+ p_c_meaning,
36
+ gamma_meaning,
37
+ theta_meaning,
38
+ r_meaning
39
+ )
40
+ from permeability.permeability.Seepage import (
41
+ calculate_permeability,
42
+ calculate_infiltration_time,
43
+ calculate_infiltration_front_position,
44
+ calculate_infiltration_front_position_with_multiple_time,
45
+ calculate_pressure_difference
46
+ )
47
+ from permeability.permeability.Capillary import (
48
+ calculate_permeability_with_capillary_correction,
49
+ calculate_infiltration_time_with_capillary_correction,
50
+ calculate_infiltration_front_position_with_capillary_correction,
51
+ calculate_infiltration_front_position_with_multiple_time_with_capillary_correction,
52
+ calculate_capillary_pressure,
53
+ calculate_pressure_difference_with_capillary_correction
54
+ )
55
+ from permeability.utils.UnitConverter import (
56
+ darcy2m2,
57
+ m22darcy
58
+ )
59
+
60
+
61
+ # mcp
62
+ mcp = FastMCP(
63
+ "Permeability MCP",
64
+ strict_input_validation=True,
65
+ mask_error_details=True,
66
+ instructions=mcp_instruction
67
+ )
68
+
69
+
70
+ # Calculate permeability
71
+ @mcp.tool(
72
+ name="calculate_permeability_by_seepage_distance",
73
+ description=permeability_calculation_instruction,
74
+ tags={"permeability", "scalar_calculation"}
75
+ )
76
+ async def calculate_permeability_by_seepage_distance(
77
+ L: Annotated[float, L_meaning],
78
+ mu: Annotated[float, mu_meaning],
79
+ phi: Annotated[float, phi_meaning],
80
+ t: Annotated[float, t_meaning],
81
+ dP: Annotated[float, dP_meaning],
82
+ p_c: Optional[Annotated[float, p_c_meaning]] = None
83
+ ) -> dict:
84
+ try:
85
+ if p_c is None:
86
+ calculation_result = calculate_permeability(
87
+ L=L,
88
+ mu=mu,
89
+ phi=phi,
90
+ t=t,
91
+ dP=dP
92
+ )
93
+ else:
94
+ calculation_result = calculate_permeability_with_capillary_correction(
95
+ L=L,
96
+ mu=mu,
97
+ phi=phi,
98
+ t=t,
99
+ dP=dP,
100
+ p_c=p_c
101
+ )
102
+ return process_mcp_calculation_result(
103
+ value=calculation_result,
104
+ unit="m^2",
105
+ meaning=K_meaning
106
+ )
107
+ except Exception as e:
108
+ raise ToolError(e)
109
+
110
+
111
+ # Infiltration time calculation
112
+ @mcp.tool(
113
+ name="calculate_infiltration_time",
114
+ description=infiltration_time_calculation_instruction,
115
+ tags={"permeability", "scalar_calculation"}
116
+ )
117
+ async def calculate_infiltration_time_tool(
118
+ L: Annotated[float, L_meaning],
119
+ mu: Annotated[float, mu_meaning],
120
+ phi: Annotated[float, phi_meaning],
121
+ K: Annotated[float, K_meaning],
122
+ dP: Annotated[float, dP_meaning],
123
+ p_c: Optional[Annotated[float, p_c_meaning]] = None
124
+ ) -> dict:
125
+ try:
126
+ if p_c is None:
127
+ calculation_result = calculate_infiltration_time(
128
+ L=L,
129
+ mu=mu,
130
+ phi=phi,
131
+ K=K,
132
+ dP=dP
133
+ )
134
+ else:
135
+ calculation_result = calculate_infiltration_time_with_capillary_correction(
136
+ L=L,
137
+ mu=mu,
138
+ phi=phi,
139
+ K=K,
140
+ dP=dP,
141
+ p_c=p_c
142
+ )
143
+ return process_mcp_calculation_result(
144
+ value=calculation_result,
145
+ unit="s",
146
+ meaning=t_meaning
147
+ )
148
+ except Exception as e:
149
+ raise ToolError(e)
150
+
151
+
152
+ # Tool for converting darcy to m2
153
+ @mcp.tool(
154
+ name="darcy_to_m2_converter",
155
+ description=darcy2m2_instruction,
156
+ tags={"permeability", "unit_converter"}
157
+ )
158
+ async def darcy_to_m2_converter(
159
+ darcyK: Annotated[float, darcyK_meaning],
160
+ ) -> dict:
161
+ calculation_result = darcy2m2(darcyK=darcyK)
162
+ return process_mcp_calculation_result(
163
+ value=calculation_result,
164
+ unit="m^2",
165
+ meaning=m2K_meaning
166
+ )
167
+
168
+
169
+ # Tool for converting m2 to darcy
170
+ @mcp.tool(
171
+ name="m2_to_darcy_converter",
172
+ description=m22darcy_instruction,
173
+ tags={"permeability", "unit_converter"}
174
+ )
175
+ async def m2_to_darcy_converter(
176
+ m2K: Annotated[float, m2K_meaning],
177
+ ) -> dict:
178
+ calculation_result = m22darcy(m2K=m2K)
179
+ return process_mcp_calculation_result(
180
+ value=calculation_result,
181
+ unit="Darcy",
182
+ meaning=darcyK_meaning
183
+ )
184
+
185
+
186
+ # Tool for calculating infiltration front position
187
+ @mcp.tool(
188
+ name="calculate_infiltration_front_position",
189
+ description=infiltration_front_position_instruction,
190
+ tags={"permeability", "scalar_calculation"}
191
+ )
192
+ async def calculate_infiltration_front_position_tool(
193
+ K: Annotated[float, K_meaning],
194
+ mu: Annotated[float, mu_meaning],
195
+ phi: Annotated[float, phi_meaning],
196
+ dP: Annotated[float, dP_meaning],
197
+ t: Annotated[float, t_meaning],
198
+ p_c: Optional[Annotated[float, p_c_meaning]] = None
199
+ ) -> dict:
200
+ try:
201
+ if p_c is None:
202
+ calculation_result = calculate_infiltration_front_position(
203
+ K=K,
204
+ mu=mu,
205
+ phi=phi,
206
+ t=t,
207
+ dP=dP
208
+ )
209
+ else:
210
+ calculation_result = calculate_infiltration_front_position_with_capillary_correction(
211
+ K=K,
212
+ mu=mu,
213
+ phi=phi,
214
+ t=t,
215
+ dP=dP,
216
+ p_c=p_c
217
+ )
218
+ return process_mcp_calculation_result(
219
+ value=calculation_result,
220
+ unit="m",
221
+ meaning=z_meaning
222
+ )
223
+ except Exception as e:
224
+ raise ToolError(e)
225
+
226
+
227
+ # Tool for calculating infiltration front position for multiple time points
228
+ @mcp.tool(
229
+ name="calculate_infiltration_front_position4multiple_times",
230
+ description=infiltration_front_position_multiple_time_instruction,
231
+ tags={"permeability", "graph_related", "vector_calculation"}
232
+ )
233
+ async def calculate_infiltration_front_position4multiple_times_tool(
234
+ K: Annotated[float, K_meaning],
235
+ mu: Annotated[float, mu_meaning],
236
+ phi: Annotated[float, phi_meaning],
237
+ dP: Annotated[float, dP_meaning],
238
+ t: Annotated[List[float], multi_t_meaning],
239
+ p_c: Optional[Annotated[float, p_c_meaning]] = None
240
+ ) -> dict:
241
+ try:
242
+ processed_t = np.array(t)
243
+ if p_c is None:
244
+ calculation_result = calculate_infiltration_front_position_with_multiple_time(
245
+ K=K,
246
+ mu=mu,
247
+ phi=phi,
248
+ t=processed_t,
249
+ dP=dP
250
+ )
251
+ else:
252
+ calculation_result = (
253
+ calculate_infiltration_front_position_with_multiple_time_with_capillary_correction(
254
+ K=K,
255
+ mu=mu,
256
+ phi=phi,
257
+ t=processed_t,
258
+ dP=dP,
259
+ p_c=p_c
260
+ )
261
+ )
262
+ return process_mcp_calculation_result(
263
+ value=calculation_result.tolist(),
264
+ unit="m",
265
+ meaning=z_meaning
266
+ )
267
+ except Exception as e:
268
+ raise ToolError(e)
269
+
270
+
271
+ # Calculate capillary pressure
272
+ @mcp.tool(
273
+ name="calculate_capillary_pressure",
274
+ description=capillary_pressure_calculation_instruction,
275
+ tags={"permeability", "scalar_calculation"}
276
+ )
277
+ async def calculate_capillary_pressure_tool(
278
+ theta: Annotated[float, theta_meaning],
279
+ r: Annotated[float, r_meaning],
280
+ gamma: Annotated[float, gamma_meaning],
281
+ ):
282
+ try:
283
+ calculation_result = calculate_capillary_pressure(
284
+ theta=theta,
285
+ r=r,
286
+ gamma=gamma
287
+ )
288
+ return process_mcp_calculation_result(
289
+ value=calculation_result,
290
+ unit="Pa",
291
+ meaning=p_c_meaning
292
+ )
293
+ except Exception as e:
294
+ raise ToolError(e)
295
+
296
+
297
+ # Calculate pressure difference
298
+ @mcp.tool(
299
+ name="calculate_pressure_difference",
300
+ description=pressure_difference_calculation_instruction,
301
+ tags={"permeability", "scalar_calculation"}
302
+ )
303
+ async def calculate_pressure_difference_tool(
304
+ L: Annotated[float, L_meaning],
305
+ mu: Annotated[float, mu_meaning],
306
+ phi: Annotated[float, phi_meaning],
307
+ K: Annotated[float, K_meaning],
308
+ t: Annotated[float, t_meaning],
309
+ p_c: Optional[Annotated[float, p_c_meaning]] = None,
310
+ ):
311
+ try:
312
+ if p_c is None:
313
+ calculation_result = calculate_pressure_difference(
314
+ L=L,
315
+ mu=mu,
316
+ phi=phi,
317
+ K=K,
318
+ t=t
319
+ )
320
+ else:
321
+ calculation_result = calculate_pressure_difference_with_capillary_correction(
322
+ L=L,
323
+ mu=mu,
324
+ phi=phi,
325
+ K=K,
326
+ t=t,
327
+ p_c=p_c
328
+ )
329
+ return process_mcp_calculation_result(
330
+ value=calculation_result,
331
+ unit="Pa",
332
+ meaning=dP_meaning
333
+ )
334
+ except Exception as e:
335
+ raise ToolError(e)
336
+
337
+
338
+ # Run
339
+ def run():
340
+ parser = argparse.ArgumentParser(description="My MCP Server")
341
+ parser.add_argument("--port", type=int, default=8000, help="Port for SSE transport")
342
+ args = parser.parse_args()
343
+ mcp.run(transport="http", host="localhost", port=args.port)
File without changes
@@ -0,0 +1,179 @@
1
+ import numpy as np
2
+
3
+
4
+ def calculate_capillary_pressure(
5
+ gamma: float,
6
+ theta: float,
7
+ r: float
8
+ ) -> float:
9
+ '''
10
+ Calculate capillary pressure using the Young-Laplace equation.
11
+ p_c = 2 · γ · cos(θ) / r
12
+ :param gamma: Surface tension of the liquid (N/m)
13
+ :param theta: Contact angle (wetting angle) (Degrees)
14
+ :param r: Equivalent pore radius (m)
15
+ :return: p_c, capillary pressure (Pa)
16
+ '''
17
+ if gamma <= 0:
18
+ raise ValueError('gamma must be greater than 0')
19
+ if r <= 0:
20
+ raise ValueError('r must be greater than 0')
21
+ rad_theta = np.deg2rad(theta)
22
+ return (2*gamma*np.cos(rad_theta))/r
23
+
24
+
25
+ def calculate_permeability_with_capillary_correction(
26
+ p_c: float,
27
+ L: float,
28
+ mu: float,
29
+ phi: float,
30
+ t: float,
31
+ dP: float,
32
+ ):
33
+ '''
34
+ Calculate permeability with capillary force correction.
35
+ K = μ · φ · L² / (2 · t · (ΔP + p_c))
36
+ :param p_c: capillary pressure (Pa)
37
+ :param L: Sample length/thickness along flow direction (m)
38
+ :param mu: Dynamic viscosity of the fluid (Pa·s)
39
+ :param phi: Porosity of the porous medium (dimensionless, 0 < phi <= 1)
40
+ :param t: Total time for fluid to fully penetrate the sample (s)
41
+ :param dP: Constant pressure difference across the sample (Pa)
42
+ :return: K, Permeability (m^2)
43
+ '''
44
+ if dP <= 0 or t <= 0:
45
+ raise ValueError("dP and t cannot be smaller than 0")
46
+ if mu <= 0:
47
+ raise ValueError("mu cannot be <= 0")
48
+ if phi > 1 or phi < 0:
49
+ raise ValueError("phi must be between 0 and 1")
50
+ if L <= 0:
51
+ raise ValueError("L must be greater than 0")
52
+ if p_c == -dP:
53
+ raise ValueError("p_c + dP cannot be equal to 0")
54
+ return (L * L * mu * phi) / (2 * t * (dP + p_c))
55
+
56
+
57
+ def calculate_infiltration_time_with_capillary_correction(
58
+ p_c: float,
59
+ L: float,
60
+ mu: float,
61
+ phi: float,
62
+ K: float,
63
+ dP: float
64
+ ) -> float:
65
+ '''
66
+ Calculate permeability with capillary force correction.
67
+ t = μ · φ · L² / (2 · K · (ΔP + p_c))
68
+ :param p_c: capillary pressure (Pa)
69
+ :param L: Sample length/thickness along flow direction (m)
70
+ :param mu: Dynamic viscosity of the fluid (Pa·s)
71
+ :param phi: Porosity of the porous medium (dimensionless, 0 < phi <= 1)
72
+ :param K: Permeability (m^2)
73
+ :param dP: Constant pressure difference across the sample (Pa)
74
+ :return: t, Total time for fluid to fully penetrate the sample (s)
75
+ '''
76
+ if K <= 0 or dP <= 0:
77
+ raise ValueError("dP and K cannot be smaller than 0")
78
+ if mu <= 0:
79
+ raise ValueError("mu cannot be <= 0")
80
+ if phi > 1 or phi < 0:
81
+ raise ValueError("phi must be between 0 and 1")
82
+ if L <= 0:
83
+ raise ValueError("L must be greater than 0")
84
+ if p_c == -dP:
85
+ raise ValueError("p_c + dP != 0")
86
+ return (mu * phi * L * L) / (2 * K * (dP+p_c))
87
+
88
+
89
+ def calculate_infiltration_front_position_with_capillary_correction(
90
+ K: float,
91
+ mu: float,
92
+ phi: float,
93
+ dP: float,
94
+ t: float,
95
+ p_c: float
96
+ ) -> float:
97
+ '''
98
+ Calculate infiltration front position with capillary force correction at given time(s).
99
+ z(t) = sqrt(2 · K · (ΔP + p_c) · t / (μ · φ))
100
+ :param K: Permeability (m^2)
101
+ :param p_c: capillary pressure (Pa)
102
+ :param mu: Dynamic viscosity of the fluid (Pa·s)
103
+ :param phi: Porosity of the porous medium (dimensionless, 0 < phi <= 1)
104
+ :param dP: Constant pressure difference across the sample (Pa)
105
+ :param t: Total time recorded for fluid to fully penetrate the sample (s)
106
+ :return: z, the infiltration front position at given time
107
+ '''
108
+ if mu <= 0 or phi <= 0:
109
+ raise ValueError("mu and phi cannot be smaller than 0")
110
+ if phi > 1 or phi < 0:
111
+ raise ValueError("phi must be between 0 and 1")
112
+ if K <= 0:
113
+ raise ValueError("K must be greater than 0")
114
+ if t < 0:
115
+ raise ValueError("t must be greater than 0")
116
+ if dP <= 0:
117
+ raise ValueError("dP must be greater than 0")
118
+ return np.sqrt((2 * K * (dP+p_c) * t) / (mu * phi))
119
+
120
+
121
+ def calculate_infiltration_front_position_with_multiple_time_with_capillary_correction(
122
+ K: float,
123
+ mu: float,
124
+ phi: float,
125
+ dP: float,
126
+ t: np.ndarray,
127
+ p_c: float
128
+ ) -> np.ndarray:
129
+ '''
130
+ Calculate infiltration front position with capillary force correction at multiple times (for graph making).
131
+ z(t) = sqrt(2 · K · (ΔP + p_c) · t / (μ · φ))
132
+ :param p_c: capillary pressure (Pa)
133
+ :param K: Permeability (m^2)
134
+ :param mu: Dynamic viscosity of the fluid (Pa·s)
135
+ :param phi: Porosity of the porous medium (dimensionless, 0 < phi <= 1)
136
+ :param dP: Constant pressure difference across the sample (Pa)
137
+ :param t: Total time recorded for multiple rounds for fluid to fully penetrate the sample (s)
138
+ :return: z, the infiltration front position at given time
139
+ '''
140
+ if mu <= 0 or phi <= 0:
141
+ raise ValueError("mu and phi cannot be smaller than 0")
142
+ if phi > 1 or phi < 0:
143
+ raise ValueError("phi must be between 0 and 1")
144
+ if K <= 0:
145
+ raise ValueError("K must be greater than 0")
146
+ if not np.all(t >= 0):
147
+ raise ValueError("t must be greater than 0")
148
+ if dP <= 0:
149
+ raise ValueError("dP must be greater than 0")
150
+ return np.sqrt((2 * K * (dP+p_c) * t) / (mu * phi))
151
+
152
+
153
+ def calculate_pressure_difference_with_capillary_correction(
154
+ L: float,
155
+ mu: float,
156
+ phi: float,
157
+ K: float,
158
+ t: float,
159
+ p_c: float
160
+ ) -> float:
161
+ '''
162
+ Calculate pressure difference using the seepage distance method with capillary correction.
163
+ ΔP = μ · φ · L² / (2 · K · t) - p_c
164
+ :param L: Sample length/thickness along flow direction (m)
165
+ :param mu: Dynamic viscosity of the fluid (Pa·s)
166
+ :param phi: Porosity of the porous medium (dimensionless, 0 < phi <= 1)
167
+ :param K: Permeability (m^2)
168
+ :param t, Total time for fluid to fully penetrate the sample (s)
169
+ :return: dP, Constant pressure difference across the sample (Pa)
170
+ '''
171
+ if K <= 0 or t <= 0:
172
+ raise ValueError("dP and K cannot be smaller than 0")
173
+ if mu <= 0:
174
+ raise ValueError("mu cannot be <= 0")
175
+ if phi > 1 or phi < 0:
176
+ raise ValueError("phi must be between 0 and 1")
177
+ if L <= 0:
178
+ raise ValueError("L must be greater than 0")
179
+ return (mu * phi * L * L) / (2 * K * t) - p_c