yaeos 0.1.1__cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.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.
yaeos/__init__.py ADDED
@@ -0,0 +1,30 @@
1
+ """Yet Another Equation-Of-State (library).
2
+
3
+ Library to use EoS-based calculations. This main module imports all the
4
+ relevant constants, procedures and objects to have better access to them.
5
+ """
6
+
7
+ from yaeos.lib import yaeos_c
8
+ from yaeos.models.excess_gibbs.nrtl import (
9
+ NRTL,
10
+ )
11
+ from yaeos.models.residual_helmholtz.cubic_eos import (
12
+ MHV,
13
+ PengRobinson76,
14
+ PengRobinson78,
15
+ QMR,
16
+ RKPR,
17
+ SoaveRedlichKwong,
18
+ )
19
+
20
+
21
+ __all__ = [
22
+ "yaeos_c",
23
+ "SoaveRedlichKwong",
24
+ "PengRobinson76",
25
+ "PengRobinson78",
26
+ "RKPR",
27
+ "QMR",
28
+ "NRTL",
29
+ "MHV",
30
+ ]
yaeos/core.py ADDED
@@ -0,0 +1,557 @@
1
+ """yaeos Python API core module.
2
+
3
+ ArModel and GeModel abstract classes definition. Also, the implementation of
4
+ the models' thermoprops methods.
5
+ """
6
+
7
+ from abc import ABC
8
+ from typing import Union
9
+
10
+ import numpy as np
11
+
12
+ from yaeos.lib import yaeos_c
13
+
14
+
15
+ class GeModel(ABC):
16
+ """Excess Gibbs (Ge) model abstract class."""
17
+
18
+ def __del__(self) -> None:
19
+ """Delete the model from the available models list (Fortran side)."""
20
+ yaeos_c.make_available_ge_models_list(self.id)
21
+
22
+
23
+ class ArModel(ABC):
24
+ """Residual Helmholtz (Ar) model abstract class."""
25
+
26
+ def lnphi_vt(
27
+ self,
28
+ moles,
29
+ volume: float,
30
+ temperature: float,
31
+ dt: bool = False,
32
+ dp: bool = False,
33
+ dn: bool = False,
34
+ ) -> Union[np.ndarray, tuple[np.ndarray, dict]]:
35
+ r"""Calculate fugacity coefficent given volume and temperature.
36
+
37
+ Calculate :math:`ln \phi_i(n,V,T)` and its derivatives with respect to
38
+ temperature, pressure and moles number.
39
+
40
+ Parameters
41
+ ----------
42
+ moles : array_like
43
+ Moles number vector [mol]
44
+ volume : float
45
+ Volume [L]
46
+ temperature : float
47
+ Temperature [K]
48
+ dt : bool, optional
49
+ Calculate temperature derivative, by default False
50
+ dp : bool, optional
51
+ Calculate pressure derivative, by default False
52
+ dn : bool, optional
53
+ Calculate moles derivative, by default False
54
+
55
+ Returns
56
+ -------
57
+ Union[np.ndarray, tuple[np.ndarray, dict]]
58
+ :math:`ln \phi_i(n,V,T)` vector or tuple with
59
+ :math:`ln \phi_i(n,V,T)` vector and derivatives dictionary if any
60
+ derivative is asked
61
+
62
+ Example
63
+ -------
64
+ .. code-block:: python
65
+
66
+ import numpy as np
67
+
68
+ from yaeos import PengRobinson76
69
+
70
+
71
+ tc = np.array([320.0, 375.0]) # critical temperatures [K]
72
+ pc = np.array([45.0, 60.0]) # critical pressures [bar]
73
+ w = np.array([0.0123, 0.045]) # acentric factors
74
+
75
+ model = PengRobinson76(tc, pc, w)
76
+
77
+ # Evaluating ln_phi only
78
+ # will print: [-1.45216274 -2.01044828]
79
+
80
+ print(model.lnphi_vt([5.0, 5.6], 1.0, 300.0))
81
+
82
+ # Asking for derivatives
83
+ # will print:
84
+ # (
85
+ # array([-1.45216274, -2.01044828]),
86
+ # {'dt': array([0.01400063, 0.01923493]), 'dp': None, 'dn': None}
87
+ # )
88
+
89
+ print(model.lnphi_vt([5.0, 5.6], 1.0, 300.0, dt=True)
90
+ """
91
+ nc = len(moles)
92
+
93
+ dt = np.empty(nc, order="F") if dt else None
94
+ dp = np.empty(nc, order="F") if dp else None
95
+ dn = np.empty((nc, nc), order="F") if dn else None
96
+
97
+ res = yaeos_c.lnphi_vt(
98
+ self.id,
99
+ moles,
100
+ volume,
101
+ temperature,
102
+ dlnphidt=dt,
103
+ dlnphidp=dp,
104
+ dlnphidn=dn,
105
+ )
106
+
107
+ if dt is None and dp is None and dn is None:
108
+ ...
109
+ else:
110
+ res = (res, {"dt": dt, "dp": dp, "dn": dn})
111
+ return res
112
+
113
+ def lnphi_pt(
114
+ self,
115
+ moles,
116
+ pressure: float,
117
+ temperature: float,
118
+ root: str = "stable",
119
+ dt: bool = False,
120
+ dp: bool = False,
121
+ dn: bool = False,
122
+ ) -> Union[np.ndarray, tuple[np.ndarray, dict]]:
123
+ r"""Calculate fugacity coefficent given pressure and temperature.
124
+
125
+ Calculate :math:`ln \phi_i(n,P,T)` and its derivatives with respect to
126
+ temperature, pressure and moles number.
127
+
128
+ Parameters
129
+ ----------
130
+ moles : array_like
131
+ Moles number vector [mol]
132
+ pressure : float
133
+ Pressure [bar]
134
+ temperature : float
135
+ Temperature [K]
136
+ root : str, optional
137
+ Volume root, use: "liquid", "vapor" or "stable", by default
138
+ "stable"
139
+ dt : bool, optional
140
+ Calculate temperature derivative, by default False
141
+ dp : bool, optional
142
+ Calculate pressure derivative, by default False
143
+ dn : bool, optional
144
+ Calculate moles derivative, by default False
145
+
146
+ Returns
147
+ -------
148
+ Union[np.ndarray, tuple[np.ndarray, dict]]
149
+ :math:`ln \phi_i(n,P,T)` vector or tuple with
150
+ :math:`ln \phi_i(n,P,T)` vector and derivatives dictionary if any
151
+ derivative is asked
152
+
153
+ Example
154
+ -------
155
+ .. code-block:: python
156
+
157
+ import numpy as np
158
+
159
+ from yaeos import PengRobinson76
160
+
161
+
162
+ tc = np.array([320.0, 375.0]) # critical temperatures [K]
163
+ pc = np.array([45.0, 60.0]) # critical pressures [bar]
164
+ w = np.array([0.0123, 0.045]) # acentric factors
165
+
166
+ model = PengRobinson76(tc, pc, w)
167
+
168
+ # Evaluating ln_phi only
169
+ # will print: [-0.10288733 -0.11909807]
170
+
171
+ print(model.lnphi_pt([5.0, 5.6], 10.0, 300.0))
172
+
173
+ # Asking for derivatives
174
+ # will print:
175
+ # (
176
+ # array([-0.10288733, -0.11909807]),
177
+ # {'dt': array([0.00094892, 0.00108809]), 'dp': None, 'dn': None}
178
+ # )
179
+
180
+ print(model.lnphi_pt([5.0, 5.6], 10.0, 300.0, dt=True)
181
+ """
182
+ nc = len(moles)
183
+
184
+ dt = np.empty(nc, order="F") if dt else None
185
+ dp = np.empty(nc, order="F") if dp else None
186
+ dn = np.empty((nc, nc), order="F") if dn else None
187
+
188
+ res = yaeos_c.lnphi_pt(
189
+ self.id,
190
+ moles,
191
+ pressure,
192
+ temperature,
193
+ root,
194
+ dlnphidt=dt,
195
+ dlnphidp=dp,
196
+ dlnphidn=dn,
197
+ )
198
+
199
+ if dt is None and dp is None and dn is None:
200
+ ...
201
+ else:
202
+ res = (res, {"dt": dt, "dp": dp, "dn": dn})
203
+ return res
204
+
205
+ def pressure(
206
+ self,
207
+ moles,
208
+ volume: float,
209
+ temperature: float,
210
+ dv: bool = False,
211
+ dt: bool = False,
212
+ dn: bool = False,
213
+ ) -> Union[float, tuple[float, dict]]:
214
+ """Calculate pressure given volume and temperature [bar].
215
+
216
+ Calculate :math:`P(n,V,T)` and its derivatives with respect to
217
+ volume, temperature and moles number.
218
+
219
+ Parameters
220
+ ----------
221
+ moles : array_like
222
+ Moles number vector [mol]
223
+ volume : float
224
+ Volume [L]
225
+ temperature : float
226
+ Temperature [K]
227
+ dv : bool, optional
228
+ Calculate volume derivative, by default False
229
+ dt : bool, optional
230
+ Calculate temperature derivative, by default False
231
+ dn : bool, optional
232
+ Calculate moles derivative, by default False
233
+
234
+ Returns
235
+ -------
236
+ Union[float, tuple[float, dict]]
237
+ Pressure or tuple with Presure and derivatives dictionary if any
238
+ derivative is asked [bar]
239
+
240
+ Example
241
+ -------
242
+ .. code-block:: python
243
+
244
+ import numpy as np
245
+
246
+ from yaeos import PengRobinson76
247
+
248
+
249
+ tc = np.array([320.0, 375.0]) # critical temperatures [K]
250
+ pc = np.array([45.0, 60.0]) # critical pressures [bar]
251
+ w = np.array([0.0123, 0.045]) # acentric factors
252
+
253
+ model = PengRobinson76(tc, pc, w)
254
+
255
+ # Evaluating pressure only
256
+ # will print: 16.011985733846956
257
+
258
+ print(model.pressure(np.array([5.0, 5.6]), 2.0, 300.0))
259
+
260
+ # Asking for derivatives
261
+ # will print:
262
+ # (
263
+ # 16.011985733846956,
264
+ # {'dv': None, 'dt': np.float64(0.7664672352866752), 'dn': None}
265
+ # )
266
+
267
+ print(model.pressure(np.array([5.0, 5.6]), 2.0, 300.0, dt=True))
268
+ """
269
+ nc = len(moles)
270
+
271
+ dv = np.empty(1, order="F") if dv else None
272
+ dt = np.empty(1, order="F") if dt else None
273
+ dn = np.empty(nc, order="F") if dn else None
274
+
275
+ res = yaeos_c.pressure(
276
+ self.id, moles, volume, temperature, dpdv=dv, dpdt=dt, dpdn=dn
277
+ )
278
+
279
+ if dt is None and dv is None and dn is None:
280
+ ...
281
+ else:
282
+ res = (
283
+ res,
284
+ {
285
+ "dv": dv if dv is None else dv[0],
286
+ "dt": dt if dt is None else dt[0],
287
+ "dn": dn,
288
+ },
289
+ )
290
+ return res
291
+
292
+ def volume(
293
+ self, moles, pressure: float, temperature: float, root: str = "stable"
294
+ ) -> float:
295
+ """Calculate volume given pressure and temperature [L].
296
+
297
+ Parameters
298
+ ----------
299
+ moles : array_like
300
+ Moles number vector [mol]
301
+ pressure : float
302
+ Pressure [bar]
303
+ temperature : float
304
+ Temperature [K]
305
+ root : str, optional
306
+ Volume root, use: "liquid", "vapor" or "stable", by default
307
+ "stable"
308
+
309
+ Returns
310
+ -------
311
+ float
312
+ Volume [L]
313
+
314
+ Example
315
+ -------
316
+ .. code-block:: python
317
+
318
+ import numpy as np
319
+
320
+ from yaeos import PengRobinson76
321
+
322
+
323
+ tc = np.array([320.0, 375.0]) # critical temperatures [K]
324
+ pc = np.array([45.0, 60.0]) # critical pressures [bar]
325
+ w = np.array([0.0123, 0.045]) # acentric factors
326
+
327
+ model = PengRobinson76(tc, pc, w)
328
+
329
+ # Evaluating stable root volume
330
+ # will print: 23.373902973572587
331
+
332
+ print(model.volume(np.array([5.0, 5.6]), 10.0, 300.0))
333
+
334
+ # Liquid root volume (not stable)
335
+ # will print: 0.8156388756398074
336
+
337
+ print(model.volume(np.array([5.0, 5.6]), 10.0, 300.0, "liquid"))
338
+ """
339
+ res = yaeos_c.volume(self.id, moles, pressure, temperature, root)
340
+ return res
341
+
342
+ def flash_pt(self, z, pressure: float, temperature: float) -> dict:
343
+ """Two-phase split with specification of temperature and pressure.
344
+
345
+ Parameters
346
+ ----------
347
+ z : array_like
348
+ Global mole fractions
349
+ pressure : float
350
+ Pressure [bar]
351
+ temperature : float
352
+ Temperature [K]
353
+
354
+ Returns
355
+ -------
356
+ dict
357
+ Flash result dictionary with keys:
358
+ - x: heavy phase mole fractions
359
+ - y: light phase mole fractions
360
+ - Vx: heavy phase volume [L]
361
+ - Vy: light phase volume [L]
362
+ - P: pressure [bar]
363
+ - T: temperature [K]
364
+ - beta: light phase fraction
365
+
366
+ Example
367
+ -------
368
+ .. code-block:: python
369
+
370
+ import numpy as np
371
+
372
+ from yaeos import PengRobinson76
373
+
374
+
375
+ tc = np.array([369.83, 507.6]) # critical temperatures [K]
376
+ pc = np.array([42.48, 30.25]) # critical pressures [bar]
377
+ w = np.array([0.152291, 0.301261]) # acentric factors
378
+
379
+ model = PengRobinson76(tc, pc, w)
380
+
381
+ # Flash calculation
382
+ # will print:
383
+ # {
384
+ # 'x': array([0.3008742, 0.6991258]),
385
+ # 'y': array([0.85437317, 0.14562683]),
386
+ # 'Vx': 0.12742569165483714,
387
+ # 'Vy': 3.218831515959867,
388
+ # 'P': 8.0,
389
+ # 'T': 350.0,
390
+ # 'beta': 0.35975821044266726
391
+ # }
392
+
393
+ print(model.flash_pt([0.5, 0.5], 8.0, 350.0))
394
+ """
395
+ x, y, pressure, temperature, volume_x, volume_y, beta = yaeos_c.flash(
396
+ self.id, z, p=pressure, t=temperature
397
+ )
398
+
399
+ flash_result = {
400
+ "x": x,
401
+ "y": y,
402
+ "Vx": volume_x,
403
+ "Vy": volume_y,
404
+ "P": pressure,
405
+ "T": temperature,
406
+ "beta": beta,
407
+ }
408
+
409
+ return flash_result
410
+
411
+ def saturation_pressure(
412
+ self, z, temperature: float, kind: str = "bubble"
413
+ ) -> dict:
414
+ """Saturation pressure at specified temperature.
415
+
416
+ Arguments
417
+ ---------
418
+ z: array_like
419
+ Global molar fractions
420
+ temperature: float
421
+ Temperature [K]
422
+ kind: str, optional
423
+ Kind of saturation point, defaults to "bubble". Options are
424
+ - "bubble"
425
+ - "dew"
426
+ - "liquid-liquid"
427
+
428
+ Returns
429
+ -------
430
+ dict
431
+ Saturation pressure calculation result dictionary with keys:
432
+ - x: heavy phase mole fractions
433
+ - y: light phase mole fractions
434
+ - Vx: heavy phase volume [L]
435
+ - Vy: light phase volume [L]
436
+ - P: pressure [bar]
437
+ - T: temperature [K]
438
+ - beta: light phase fraction
439
+
440
+ Example
441
+ -------
442
+ .. code-block:: python
443
+
444
+ import numpy as np
445
+
446
+ from yaeos import PengRobinson76
447
+
448
+
449
+ tc = np.array([369.83, 507.6]) # critical temperatures [K]
450
+ pc = np.array([42.48, 30.25]) # critical pressures [bar]
451
+ w = np.array([0.152291, 0.301261]) # acentric factors
452
+
453
+ model = PengRobinson76(tc, pc, w)
454
+
455
+ # Saturation pressure calculation
456
+ # will print:
457
+ # {
458
+ # 'x': array([0.5, 0.5]),
459
+ # 'y': array([0.9210035 , 0.07899651]),
460
+ # 'Vx': 0.11974125553488875,
461
+ # 'Vy': 1.849650524323853,
462
+ # 'T': 350.0,
463
+ # 'P': 12.990142036059941,
464
+ # 'beta': 0.0
465
+ # }
466
+
467
+ print(model.saturation_pressure(np.array([0.5, 0.5]), 350.0))
468
+ """
469
+ p, x, y, volume_x, volume_y, beta = yaeos_c.saturation_pressure(
470
+ self.id, z, temperature, kind
471
+ )
472
+
473
+ return {
474
+ "x": x,
475
+ "y": y,
476
+ "Vx": volume_x,
477
+ "Vy": volume_y,
478
+ "T": temperature,
479
+ "P": p,
480
+ "beta": beta,
481
+ }
482
+
483
+ def phase_envelope_pt(
484
+ self,
485
+ z,
486
+ kind: str = "bubble",
487
+ max_points: int = 300,
488
+ t0: float = 150.0,
489
+ p0: float = 1.0,
490
+ ) -> dict:
491
+ """Two phase envelope calculation (PT).
492
+
493
+ Parameters
494
+ ----------
495
+ z : array_like
496
+ Global mole fractions
497
+ kind : str, optional
498
+ Kind of saturation point to start the envelope calculation,
499
+ defaults to "bubble". Options are
500
+ - "bubble"
501
+ - "dew"
502
+ max_points : int, optional
503
+ Envelope's maximum points to calculate (T, P), by default 300
504
+ t0 : float, optional
505
+ Initial guess for temperature [K] for the saturation point of kind:
506
+ `kind`, by default 150.0
507
+ p0 : float, optional
508
+ Initial guess for pressure [bar] for the saturation point of kind:
509
+ `kind`, by default 1.0
510
+
511
+ Returns
512
+ -------
513
+ dict
514
+ Envelope calculation result dictionary with keys:
515
+ - Ts: temperatures [K]
516
+ - Ps: pressures [bar]
517
+ - Tcs: critical temperatures [K]
518
+ - Pcs: critical pressures [bar]
519
+
520
+ Example
521
+ -------
522
+ .. code-block:: python
523
+
524
+ import numpy as np
525
+
526
+ import matplotlib.pyplot as plt
527
+
528
+ from yaeos import PengRobinson76
529
+
530
+
531
+ tc = np.array([369.83, 507.6]) # critical temperatures [K]
532
+ pc = np.array([42.48, 30.25]) # critical pressures [bar]
533
+ w = np.array([0.152291, 0.301261]) # acentric factors
534
+
535
+ model = PengRobinson76(tc, pc, w)
536
+
537
+ # Two phase envelope calculation and plot
538
+ env = model.phase_envelope_pt(
539
+ np.array([0.5, 0.5]),
540
+ t0=150.0,
541
+ p0=1.0
542
+ )
543
+
544
+ plt.plot(env["Ts"], env["Ps"])
545
+ plt.scatter(env["Tcs"], env["Pcs"])
546
+ """
547
+ ts, ps, tcs, pcs = yaeos_c.pt2_phase_envelope(
548
+ self.id, z, kind=kind, t0=t0, p0=p0, max_points=max_points
549
+ )
550
+
551
+ res = {"Ts": ts, "Ps": ps, "Tcs": tcs, "Pcs": pcs}
552
+
553
+ return res
554
+
555
+ def __del__(self) -> None:
556
+ """Delete the model from the available models list (Fortran side)."""
557
+ yaeos_c.make_available_ar_models_list(self.id)
yaeos/lib/__init__.py ADDED
@@ -0,0 +1,9 @@
1
+ """yaeos_c module.
2
+
3
+ This module provides the yaeos_c module, which is a Python interface to the
4
+ yaeos C API compiled with f2py.
5
+ """
6
+
7
+ from yaeos.lib.yaeos_python import yaeos_c
8
+
9
+ __all__ = ["yaeos_c"]
@@ -0,0 +1,22 @@
1
+ """Models module.
2
+
3
+ Yaeos models module. This module provides the following submodules:
4
+
5
+ - excess_gibbs: Excess Gibbs energy models
6
+ - NRTL: non-random two-liquid model
7
+
8
+ - residual_helmholtz: Residual Helmholtz energy models
9
+ - Cubic EoS:
10
+ - PengRobinson76: Peng-Robinson model (1976)
11
+ - PengRobinson78: Peng-Robinson model (1978)
12
+ - SoaveRedlichKwong: Soave-Redlich-Kwong model
13
+ - RKPR: RKPR model
14
+ - Mixing rules: mixing rules for cubic EoS
15
+ - QMR: cuadratic mixing rule
16
+ - MHV: modified Huron-Vidal mixing rule
17
+ """
18
+
19
+ from . import excess_gibbs, residual_helmholtz
20
+
21
+
22
+ __all__ = ["excess_gibbs", "residual_helmholtz"]
@@ -0,0 +1,12 @@
1
+ """Gibbs Excess Models module.
2
+
3
+ Yaeos Gibbs excess module. This module provides the following submodules:
4
+
5
+ - excess_gibbs: Excess Gibbs energy models
6
+ - NRTL: non-random two-liquid model
7
+ """
8
+
9
+ from .nrtl import NRTL
10
+
11
+
12
+ __all__ = ["NRTL"]
@@ -0,0 +1,49 @@
1
+ """Non-random two-liquid model (NRTL) module."""
2
+
3
+ from yaeos.core import GeModel
4
+ from yaeos.lib import yaeos_c
5
+
6
+
7
+ class NRTL(GeModel):
8
+ """Non-random two-liquid model (NRTL) class.
9
+
10
+ Parameters
11
+ ----------
12
+ a : array_like
13
+ NRTL aij parameters matrix
14
+ b : array_like
15
+ NRTL bij parameters matrix
16
+ c : array_like
17
+ NRTL cij parameters matrix
18
+
19
+ Attributes
20
+ ----------
21
+ a : array_like
22
+ NRTL aij parameters matrix
23
+ b : array_like
24
+ NRTL bij parameters matrix
25
+ c : array_like
26
+ NRTL cij parameters matrix
27
+ id : int
28
+ NRTL model ID
29
+
30
+ Example
31
+ -------
32
+ .. code-block:: python
33
+
34
+ import numpy as np
35
+
36
+ from yaeos import NRTL
37
+
38
+ a = np.array([[0, 0.3], [0.3, 0]])
39
+ b = np.array([[0, 0.4], [0.4, 0]])
40
+ c = np.array([[0, 0.5], [0.5, 0]])
41
+
42
+ nrtl = NRTL(a, b, c)
43
+ """
44
+
45
+ def __init__(self, a, b, c) -> None:
46
+ self.a = a
47
+ self.b = b
48
+ self.c = c
49
+ self.id = yaeos_c.nrtl(a, b, c)
@@ -0,0 +1,19 @@
1
+ """Residual Helmholtz energy models module.
2
+
3
+ Yaeos Residual Helmholtz module. This module provides the following submodules:
4
+
5
+ - residual_helmholtz: Residual Helmholtz energy models
6
+ - Cubic EoS:
7
+ - PengRobinson76: Peng-Robinson model (1976)
8
+ - PengRobinson78: Peng-Robinson model (1978)
9
+ - SoaveRedlichKwong: Soave-Redlich-Kwong model
10
+ - RKPR: RKPR model
11
+ - Mixing rules: mixing rules for cubic EoS
12
+ - QMR: cuadratic mixing rule
13
+ - MHV: modified Huron-Vidal mixing rule
14
+ """
15
+
16
+ from . import cubic_eos
17
+
18
+
19
+ __all__ = ["cubic_eos"]
@@ -0,0 +1,34 @@
1
+ """Cubic EoS module.
2
+
3
+ Implemented models:
4
+
5
+ - Cubic EoS:
6
+ - PengRobinson76: Peng-Robinson model (1976)
7
+ - PengRobinson78: Peng-Robinson model (1978)
8
+ - SoaveRedlichKwong: Soave-Redlich-Kwong model
9
+ - RKPR: RKPR model
10
+ - Mixing rules: mixing rules for cubic EoS
11
+ - QMR: cuadratic mixing rule
12
+ - MHV: modified Huron-Vidal mixing rule
13
+ """
14
+
15
+ from .cubic_eos import (
16
+ CubicEoS,
17
+ PengRobinson76,
18
+ PengRobinson78,
19
+ RKPR,
20
+ SoaveRedlichKwong,
21
+ )
22
+ from .mixing_rules import CubicMixRule, MHV, QMR
23
+
24
+
25
+ __all__ = [
26
+ "CubicEoS",
27
+ "PengRobinson76",
28
+ "PengRobinson78",
29
+ "SoaveRedlichKwong",
30
+ "RKPR",
31
+ "CubicMixRule",
32
+ "QMR",
33
+ "MHV",
34
+ ]
@@ -0,0 +1,335 @@
1
+ """Cubic EoS implementations module."""
2
+
3
+ from yaeos.core import ArModel
4
+ from yaeos.lib import yaeos_c
5
+ from yaeos.models.residual_helmholtz.cubic_eos.mixing_rules import CubicMixRule
6
+
7
+
8
+ class CubicEoS(ArModel):
9
+ """Cubic equation of state base class.
10
+
11
+ Parameters
12
+ ----------
13
+ critical_temperatures : array_like
14
+ Critical temperatures vector [K]
15
+ critical_pressures : array_like
16
+ Critical pressures vector [bar]
17
+ acentric_factors : array_like
18
+ Acentric factors vector
19
+
20
+ Attributes
21
+ ----------
22
+ nc : int
23
+ Number of components
24
+ tc : array_like
25
+ Critical temperatures vector [K]
26
+ pc : array_like
27
+ Critical pressures vector [bar]
28
+ w : array_like
29
+ Acentric factors vector
30
+ """
31
+
32
+ def __init__(
33
+ self,
34
+ critical_temperatures,
35
+ critical_pressures,
36
+ acentric_factors,
37
+ ) -> None:
38
+ nc = len(critical_temperatures)
39
+ self.nc = nc
40
+ self.tc = critical_temperatures
41
+ self.pc = critical_pressures
42
+ self.w = acentric_factors
43
+
44
+ def set_mixrule(self, mixrule: CubicMixRule) -> None:
45
+ """Set the mixing rule for the EoS.
46
+
47
+ Parameters
48
+ ----------
49
+ mixrule : CubicMixRule
50
+ Mixing rule object
51
+ """
52
+ self.mixrule = mixrule
53
+ self.mixrule.set_mixrule(self.id)
54
+
55
+
56
+ class PengRobinson76(CubicEoS):
57
+ """Peng-Robinson 1976 cubic equation of state.
58
+
59
+ Parameters
60
+ ----------
61
+ critical_temperatures : array_like
62
+ Critical temperatures vector [K]
63
+ critical_pressures : array_like
64
+ Critical pressures vector [bar]
65
+ acentric_factors : array_like
66
+ Acentric factors vector
67
+ mixrule : CubicMixRule, optional
68
+ Mixing rule object. If no provided the quadratric mixing rule (QMR)
69
+ with zero for kij and lij parameters is set, by default None
70
+
71
+ Attributes
72
+ ----------
73
+ nc : int
74
+ Number of components
75
+ critical_temperatures : array_like
76
+ Critical temperatures vector [K]
77
+ critical_pressures : array_like
78
+ Critical pressures vector [bar]
79
+ acentric_factors : array_like
80
+ Acentric factors vector
81
+ id : int
82
+ EoS identifier
83
+ mixrule : CubicMixRule
84
+ Mixing rule object
85
+
86
+ Example
87
+ -------
88
+ .. code-block:: python
89
+
90
+ from yaeos import PengRobinson76
91
+
92
+ tc = [190.56, 305.32] # Critical temperatures [K]
93
+ pc = [45.99, 48.72] # Critical pressures [bar]
94
+ w = [0.0115, 0.0985] # Acentric factors
95
+
96
+ pr76 = PengRobinson76(tc, pc, w)
97
+ """
98
+
99
+ name = "PengRobinson76"
100
+
101
+ def __init__(
102
+ self,
103
+ critical_temperatures,
104
+ critical_pressures,
105
+ acentric_factors,
106
+ mixrule: CubicMixRule = None,
107
+ ) -> None:
108
+
109
+ super(PengRobinson76, self).__init__(
110
+ critical_temperatures,
111
+ critical_pressures,
112
+ acentric_factors,
113
+ )
114
+ self.id = yaeos_c.pr76(self.tc, self.pc, self.w)
115
+ self.mixrule = mixrule
116
+ if mixrule:
117
+ mixrule.set_mixrule(self.id)
118
+
119
+
120
+ class PengRobinson78(CubicEoS):
121
+ """Peng-Robinson 1978 cubic equation of state.
122
+
123
+ Parameters
124
+ ----------
125
+ critical_temperatures : array_like
126
+ Critical temperatures vector [K]
127
+ critical_pressures : array_like
128
+ Critical pressures vector [bar]
129
+ acentric_factors : array_like
130
+ Acentric factors vector
131
+ mixrule : CubicMixRule, optional
132
+ Mixing rule object. If no provided the quadratric mixing rule (QMR)
133
+ with zero for kij and lij parameters is set, by default None
134
+
135
+ Attributes
136
+ ----------
137
+ nc : int
138
+ Number of components
139
+ critical_temperatures : array_like
140
+ Critical temperatures vector [K]
141
+ critical_pressures : array_like
142
+ Critical pressures vector [bar]
143
+ acentric_factors : array_like
144
+ Acentric factors vector
145
+ id : int
146
+ EoS identifier
147
+ mixrule : CubicMixRule
148
+ Mixing rule object
149
+
150
+ Example
151
+ -------
152
+ .. code-block:: python
153
+
154
+ from yaeos import PengRobinson78
155
+
156
+ tc = [190.56, 305.32] # Critical temperatures [K]
157
+ pc = [45.99, 48.72] # Critical pressures [bar]
158
+ w = [0.0115, 0.0985] # Acentric factors
159
+
160
+ pr78 = PengRobinson78(tc, pc, w)
161
+ """
162
+
163
+ name = "PengRobinson78"
164
+
165
+ def __init__(
166
+ self,
167
+ critical_temperatures,
168
+ critical_pressures,
169
+ acentric_factors,
170
+ mixrule: CubicMixRule = None,
171
+ ) -> None:
172
+
173
+ super(PengRobinson78, self).__init__(
174
+ critical_temperatures,
175
+ critical_pressures,
176
+ acentric_factors,
177
+ )
178
+ self.id = yaeos_c.pr78(self.tc, self.pc, self.w)
179
+ self.mixrule = mixrule
180
+ if mixrule:
181
+ mixrule.set_mixrule(self.id)
182
+
183
+
184
+ class SoaveRedlichKwong(CubicEoS):
185
+ """Soave-Redlich-Kwong cubic equation of state.
186
+
187
+ Parameters
188
+ ----------
189
+ critical_temperatures : array_like
190
+ Critical temperatures vector [K]
191
+ critical_pressures : array_like
192
+ Critical pressures vector [bar]
193
+ acentric_factors : array_like
194
+ Acentric factors vector
195
+ mixrule : CubicMixRule, optional
196
+ Mixing rule object. If no provided the quadratric mixing rule (QMR)
197
+ with zero for kij and lij parameters is set, by default None
198
+
199
+ Attributes
200
+ ----------
201
+ nc : int
202
+ Number of components
203
+ critical_temperatures : array_like
204
+ Critical temperatures vector [K]
205
+ critical_pressures : array_like
206
+ Critical pressures vector [bar]
207
+ acentric_factors : array_like
208
+ Acentric factors vector
209
+ id : int
210
+ EoS identifier
211
+ mixrule : CubicMixRule
212
+ Mixing rule object
213
+
214
+ Example
215
+ -------
216
+ .. code-block:: python
217
+
218
+ from yaeos import SoaveRedlichKwong
219
+
220
+ tc = [190.56, 305.32] # Critical temperatures [K]
221
+ pc = [45.99, 48.72] # Critical pressures [bar]
222
+ w = [0.0115, 0.0985] # Acentric factors
223
+
224
+ srk = SoaveRedlichKwong(tc, pc, w)
225
+ """
226
+
227
+ name = "SoaveReldichKwong"
228
+
229
+ def __init__(
230
+ self,
231
+ critical_temperatures,
232
+ critical_pressures,
233
+ acentric_factors,
234
+ mixrule: CubicMixRule = None,
235
+ ) -> None:
236
+
237
+ super(SoaveRedlichKwong, self).__init__(
238
+ critical_temperatures,
239
+ critical_pressures,
240
+ acentric_factors,
241
+ )
242
+ self.id = yaeos_c.srk(self.tc, self.pc, self.w)
243
+ self.mixrule = mixrule
244
+ if mixrule:
245
+ mixrule.set_mixrule(self.id)
246
+
247
+
248
+ class RKPR(CubicEoS):
249
+ """RKPR cubic equation of state.
250
+
251
+ Parameters
252
+ ----------
253
+ critical_temperatures : array_like
254
+ Critical temperatures vector [K]
255
+ critical_pressures : array_like
256
+ Critical pressures vector [bar]
257
+ acentric_factors : array_like
258
+ Acentric factors vector
259
+ critical_z : array_like
260
+ Critical compressibility factor vector
261
+ k : array_like, optional
262
+ k parameter, by default None
263
+ delta_1 : array_like, optional
264
+ delta_1 parameter, by default None
265
+ mixrule : CubicMixRule, optional
266
+ Mixing rule object. If no provided the quadratric mixing rule (QMR)
267
+ with zero for kij and lij parameters is set, by default None
268
+
269
+ Attributes
270
+ ----------
271
+ nc : int
272
+ Number of components
273
+ critical_temperatures : array_like
274
+ Critical temperatures vector [K]
275
+ critical_pressures : array_like
276
+ Critical pressures vector [bar]
277
+ acentric_factors : array_like
278
+ Acentric factors vector
279
+ zc : array_like
280
+ Critical compressibility factor vector
281
+ id : int
282
+ EoS identifier
283
+ mixrule : CubicMixRule
284
+ Mixing rule object
285
+
286
+ Example
287
+ -------
288
+ .. code-block:: python
289
+
290
+ from yaeos import RKPR
291
+
292
+ tc = [190.56, 305.32] # Critical temperatures [K]
293
+ pc = [45.99, 48.72] # Critical pressures [bar]
294
+ w = [0.0115, 0.0985] # Acentric factors
295
+ zc = [0.27, 0.28] # Critical compressibility factor
296
+
297
+ rkpr = RKPR(tc, pc, w, zc)
298
+ """
299
+
300
+ name = "RKPR"
301
+
302
+ def __init__(
303
+ self,
304
+ critical_temperatures,
305
+ critical_pressures,
306
+ acentric_factors,
307
+ critical_z,
308
+ k=None,
309
+ delta_1=None,
310
+ mixrule: CubicMixRule = None,
311
+ ) -> None:
312
+
313
+ super(RKPR, self).__init__(
314
+ critical_temperatures,
315
+ critical_pressures,
316
+ acentric_factors,
317
+ )
318
+ self.zc = critical_z
319
+
320
+ match (k is None, delta_1 is None):
321
+ case (True, True):
322
+ self.id = yaeos_c.rkpr(self.tc, self.pc, self.w, self.zc)
323
+ case (False, True):
324
+ self.id = yaeos_c.rkpr(self.tc, self.pc, self.w, self.zc, k=k)
325
+ case (True, False):
326
+ self.id = yaeos_c.rkpr(
327
+ self.tc, self.pc, self.w, self.zc, delta_1=delta_1
328
+ )
329
+ case (False, False):
330
+ self.id = yaeos_c.rkpr(
331
+ self.tc, self.pc, self.w, self.zc, k=k, delta_1=delta_1
332
+ )
333
+ self.mixrule = mixrule
334
+ if mixrule:
335
+ mixrule.set_mixrule(self.id)
@@ -0,0 +1,138 @@
1
+ """Cubic EoS mixing rules implementations module."""
2
+
3
+ from abc import ABC, abstractmethod
4
+
5
+ from yaeos.core import GeModel
6
+ from yaeos.lib import yaeos_c
7
+
8
+
9
+ class CubicMixRule(ABC):
10
+ """Cubic mix rule abstract class."""
11
+
12
+ @abstractmethod
13
+ def set_mixrule(self, ar_model_id: int) -> None:
14
+ """Set mix rule abstract method.
15
+
16
+ Changes the default mixing rule of the given cubic EoS model.
17
+
18
+ Parameters
19
+ ----------
20
+ ar_model_id : int
21
+ ID of the cubic EoS model
22
+
23
+ Raises
24
+ ------
25
+ NotImplementedError
26
+ Abstract error, this method must be implemented in the subclass
27
+ """
28
+ raise NotImplementedError
29
+
30
+
31
+ class QMR(CubicMixRule):
32
+ """Quadratic mixing rule.
33
+
34
+ Parameters
35
+ ----------
36
+ kij : array_like
37
+ kij binary interaction parameters matrix
38
+ lij : array_like
39
+ lij binary interaction parameters matrix
40
+
41
+ Attributes
42
+ ----------
43
+ kij : array_like
44
+ kij binary interaction parameters matrix
45
+ lij : array_like
46
+ lij binary interaction parameters matrix
47
+
48
+ Example
49
+ -------
50
+ .. code-block:: python
51
+
52
+ from yaeos import QMR, SoaveRedlichKwong
53
+
54
+ kij = [[0.0, 0.1], [0.1, 0.0]]
55
+ lij = [[0.0, 0.02], [0.02, 0.0]]
56
+
57
+ mixrule = QMR(kij, lij) # Quadratic mixing rule instance
58
+
59
+ tc = [305.32, 469.7] # critical temperature [K]
60
+ pc = [48.72, 33.7] # critical pressure [bar]
61
+ w = [0.0995, 0.152] # acentric factor
62
+
63
+ model = SoaveRedlichKwong(tc, pc, w, mixrule)
64
+ """
65
+
66
+ def __init__(self, kij, lij) -> None:
67
+ self.kij = kij
68
+ self.lij = lij
69
+
70
+ def set_mixrule(self, ar_model_id: int) -> None:
71
+ """Set quadratic mix rule method.
72
+
73
+ Parameters
74
+ ----------
75
+ ar_model_id : int
76
+ ID of the cubic EoS model
77
+ """
78
+ yaeos_c.set_qmr(ar_model_id, self.kij, self.lij)
79
+
80
+
81
+ class MHV(CubicMixRule):
82
+ """Modified Huron-Vidal mixing rule.
83
+
84
+ Parameters
85
+ ----------
86
+ ge : GeModel
87
+ Excess Gibbs energy model
88
+ q : float
89
+ q parameter. Use:
90
+ q = -0.594 for Soave-Redlich-Kwong
91
+ q = -0.53 for Peng-Robinson
92
+ q = -0.85 for Van der Waals
93
+ lij : array_like, optional
94
+ lij binary interaction parameters matrix, by default None
95
+
96
+ Attributes
97
+ ----------
98
+ ge : GeModel
99
+ Excess Gibbs energy model
100
+ q : float
101
+ q parameter
102
+ lij : array_like
103
+ lij binary interaction parameters matrix
104
+
105
+ Example
106
+ -------
107
+ .. code-block:: python
108
+
109
+ from yaeos import MHV, SoaveRedlichKwong, NRTL
110
+
111
+ tc = [647.14, 513.92] # critical temperature [K]
112
+ pc = [220.64, 61.48] # critical pressure [bar]
113
+ w = [0.344, 0.649] # acentric factor
114
+
115
+ a = [[0, 3.458], [-0.801, 0]] # NRTL aij parameters
116
+ b = [[0, -586.1], [246.2, 0]] # NRTL bij parameters
117
+ c = [[0, 0.3], [0.3, 0]] # NRTL cij parameters
118
+
119
+ ge_model = NRTL(a, b, c)
120
+ mixrule = MHV(ge_model, q=-0.53)
121
+
122
+ model_mhv = PengRobinson76(tc, pc, w, mixrule)
123
+ """
124
+
125
+ def __init__(self, ge: GeModel, q: float, lij=None) -> None:
126
+ self.ge = ge
127
+ self.q = q
128
+ self.lij = lij
129
+
130
+ def set_mixrule(self, ar_model_id: int) -> None:
131
+ """Set modified Huron-Vidal mix rule method.
132
+
133
+ Parameters
134
+ ----------
135
+ ar_model_id : int
136
+ ID of the cubic EoS model
137
+ """
138
+ yaeos_c.set_mhv(ar_model_id, self.ge.id, self.q)
@@ -0,0 +1,42 @@
1
+ Metadata-Version: 2.1
2
+ Name: yaeos
3
+ Version: 0.1.1
4
+ Summary: Thermodynamic modelling with Equation of State
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: numpy
7
+ Description-Content-Type: text/markdown
8
+
9
+ # yaeos Python bindings
10
+ THIS IS A WIP SO THE API WILL DRASTICALLY CHANGE WITH TIME
11
+
12
+ Set of Python bindings to call `yaeos` functions and models.
13
+
14
+ Editable installation
15
+
16
+ ```
17
+ cd python
18
+ pip install -r requirements-build.txt
19
+ pip install -e . --no-build-isolation
20
+ ```
21
+
22
+ If you want to install on your environment instead
23
+
24
+ ```shell
25
+ pip install .
26
+ ```
27
+
28
+ To check if the installation worked correctly:
29
+
30
+ ```python
31
+ from yaeos import PengRobinson76
32
+
33
+ import numpy as np
34
+
35
+ model = PengRobinson76(np.array([320, 375]), np.array([30, 45]), np.array([0.0123, 0.045]), mr)
36
+
37
+ model.lnphi_vt(np.array([5.0, 4.0]), 2.0, 303.15)
38
+ ```
39
+
40
+ ```
41
+ {'ln_phi': array([0.47647471, 0.35338115]), 'dt': None, 'dp': None, 'dn': None}
42
+ ```
@@ -0,0 +1,19 @@
1
+ yaeos.libs/liblapack-1ad85175.so.3.4.2,sha256=wrfEW65bG_XaXB2gB_JZR24uf8UxvWTrvVe6nIqfwu4,5682809
2
+ yaeos.libs/libquadmath-96973f99.so.0.0.0,sha256=k0wi3tDn0WnE1GeIdslgUa3z2UVF2pYvYLQWWbB12js,247609
3
+ yaeos.libs/libgfortran-91cc3cb1.so.3.0.0,sha256=VePrZzBsL_F-b4oIEOqg3LJulM2DkkxQZdUEDoeBRgg,1259665
4
+ yaeos.libs/libgfortran-040039e1.so.5.0.0,sha256=FK-zEpsai1C8QKOwggx_EVLqm8EBIaqxUpQ_cFdHKIY,2686065
5
+ yaeos.libs/libblas-357956a1.so.3.4.2,sha256=eLqolYX0nkk2PP64pkqa0Nif8hllaovrJMGbx8jU5W0,374265
6
+ yaeos-0.1.1.dist-info/RECORD,,
7
+ yaeos-0.1.1.dist-info/WHEEL,sha256=sZM_NeUMz2G4fDenMf11eikcCxcLaQWiYRmjwQBavQs,137
8
+ yaeos-0.1.1.dist-info/METADATA,sha256=YVZPquTLIAItFG_32wy3SWcr_A7jsaq9OAJPLf9-esw,886
9
+ yaeos/__init__.py,sha256=ZTMBNOaRmrcBEv6YLWyJdTKs0hX0VaMHP6_KGE4JI5I,578
10
+ yaeos/core.py,sha256=Bp4Y9LBt8EAk6S8QaZJo0pRD7WAomfBygn0YxrxQBgg,16239
11
+ yaeos/lib/__init__.py,sha256=JoG2sgKPrqe_TbvRI9bYXU0U_SF-GplchencGp9nNT0,199
12
+ yaeos/lib/yaeos_python.cpython-310-x86_64-linux-gnu.so,sha256=mQ7z8vGGGh4AlbCC4JVb6Z8Mkd0CeX12s5iTubVMtdY,10195929
13
+ yaeos/models/__init__.py,sha256=oH8vxuM-mMai2qeeaza0RK9KC3q-icGofg_I2t9ELaM,667
14
+ yaeos/models/residual_helmholtz/__init__.py,sha256=OWgvPQlbfyF83UVxQih_9FeAJFBrhsDSc_BWfiYpqIA,573
15
+ yaeos/models/residual_helmholtz/cubic_eos/mixing_rules.py,sha256=E8NFikKT8TxXDTUCSaKrX_IPFevUhVc4WXdMlGLQ5As,3600
16
+ yaeos/models/residual_helmholtz/cubic_eos/cubic_eos.py,sha256=r0z48oIeBFGRN_E8f9Jt6-u100epzb_Y-UeTN_i1c-Y,9169
17
+ yaeos/models/residual_helmholtz/cubic_eos/__init__.py,sha256=GM0qMwru74eSBXqVSuwxfFgK_NB3HWx9RM6ndlKRWpU,671
18
+ yaeos/models/excess_gibbs/nrtl.py,sha256=U7uLp-SLdjO-By3FSiljO5apyk4AAhbbWKK7a0kKuLg,1023
19
+ yaeos/models/excess_gibbs/__init__.py,sha256=sq1wetoEjgZB5iBZdECz-OB1bH9g0j9Ru7NuF_PaW8U,239
@@ -0,0 +1,6 @@
1
+ Wheel-Version: 1.0
2
+ Generator: meson
3
+ Root-Is-Purelib: false
4
+ Tag: cp310-cp310-manylinux_2_17_x86_64
5
+ Tag: cp310-cp310-manylinux2014_x86_64
6
+
Binary file
Binary file
Binary file
Binary file
Binary file