• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jjgomera / pychemqt / 9884aeeb-db0a-40bd-9404-6d7422e6d7b0

29 Jul 2025 01:51PM UTC coverage: 72.181% (-0.02%) from 72.199%
9884aeeb-db0a-40bd-9404-6d7422e6d7b0

push

circleci

jjgomera
Merge branch 'master' of https://github.com/jjgomera/pychemqt

30 of 130 new or added lines in 15 files covered. (23.08%)

702 existing lines in 22 files now uncovered.

28858 of 39980 relevant lines covered (72.18%)

0.72 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

7.76
/lib/refProp.py
1
#!/usr/bin/python3
2
# -*- coding: utf-8 -*-
3

4
"""Pychemqt, Chemical Engineering Process simulator
5
Copyright (C) 2009-2025, Juan José Gómez Romera <jjgomera@gmail.com>
6

7
This program is free software: you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation, either version 3 of the License, or
10
(at your option) any later version.
11

12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
GNU General Public License for more details.
16

17
You should have received a copy of the GNU General Public License
18
along with this program.  If not, see <http://www.gnu.org/licenses/>.
19

20

21
Library to multiparameter equation of state calculation using refprop and
22
the python binding from https://github.com/BenThelen/python-refprop. This \
23
library implement an old unnofficial library wrapper compatible only \
24
with Refprop v.9, refprop dll must be installed from NIST package.
25

26
If available, this is a optional speed up method for mEoS internal library
27

28
All the functionality is included in the main class:
29

30
  * :class:`RefProp`: Stream definition using refProp external library
31

32
API reference
33
-------------
34

35
"""
36

37

38
import sys
1✔
39

40
try:
1✔
41
    import refprop
1✔
42
except ImportError:
1✔
43
    pass
1✔
44

45
from lib import unidades, mEoS
1✔
46
# from lib.config import Preferences
47
from lib.mezcla import mix_unitmassflow, mix_unitmolarflow
1✔
48
from lib.thermo import ThermoRefProp
1✔
49

50

51
# TODO: Implement the official python wrapper compatible too with REFPROP v.10
52
# https://github.com/usnistgov/REFPROP-wrappers/tree/master/wrappers/python
53

54

55
__doi__ = {
1✔
56
    1:
57
        {"autor": "Lemmon, E.W., Huber, M.L., McLinden, M.O.",
58
         "title": "NIST Standard Reference Database 23:  Reference Fluid"
59
                  "Thermodynamic and Transport Properties-REFPROP, Version"
60
                  "9.1, National Institute of Standards and Technology,"
61
                  "Standard Reference Data Program, Gaithersburg, 2013.",
62
         "ref": "",
63
         "doi": ""},
64
    2:
65
        {"autor": "Thelen, B.",
66
         "title": "Python refprop wrapper, "
67
                  "https://github.com/BenThelen/python-refprop",
68
         "ref": "",
69
         "doi": ""},
70
    3:
71
        {"autor": "Huber, M.L., Lemmon, E.W., Bell, I.H., McLinden, M.O.",
72
         "title": "The NIST REFPROP Database for Highly Accurate Properties "
73
                  "of Industrially Importants Fluids",
74
         "ref": "Ind. Eng. Chem. Res. 61(42) (2022) 15449-15472",
75
         "doi": "10.1021/acs.iecr.2c01427"}}
76

77

78
# Automatic loading of refprop name from meos subclass _refPropName property
79
__all__ = {}
1✔
80
noIds = []
1✔
81
for cmp in mEoS.__all__:
1✔
82
    if cmp.id and cmp._refPropName:
1✔
83
        __all__[cmp.id] = cmp._refPropName
1✔
84
    elif cmp._refPropName:
1✔
85
        noIds.append(cmp._refPropName)
1✔
86

87

88
class RefProp(ThermoRefProp):
1✔
89
    """
90
    Stream class using refProp external library
91
    Parameters needed to define it are:
92

93
        -ref: reference state
94
        -ids: index of fluid
95
        -fraccionMolar: molar fraction
96

97
        -T: Temperature, Kelvin
98
        -P: Pressure, Pa
99
        -rho: Density, kg/m3
100
        -H: Enthalpy, J/kg
101
        -S: Entropy, J/kgK
102
        -U: Internal energy, J/kg
103
        -x: Quality, -
104

105
    setref parameters
106
    setref(hrf='DEF', ixflag=1, x0=[1], h0=0, s0=0, t0=273, p0=100):
107
        hrf--reference state for thermodynamic calculations [character*3]
108
            'NBP':  h,s = 0 at normal boiling point(s)
109
            'ASH':  h,s = 0 for sat liquid at -40 C (ASHRAE convention)
110
            'IIR':  h = 200, s = 1.0 for sat liq at 0 C (IIR convention)
111
            'DEF':  default reference state as specified in fluid file is
112
                applied to each component (ixflag = 1 is used)
113
            'OTH':  other, as specified by h0, s0, t0, p0 (real gas state)
114
            'OT0':  other, as specified by h0, s0, t0, p0 (ideal gas state)
115
            '???':  change hrf to the current reference state and exit.
116
        ixflag--composition flag:
117
            1 = ref state applied to pure components
118
            2 = ref state applied to mixture icomp
119
        following input has meaning only if ixflag = 2
120
            x0--composition for which h0, s0 apply; list(1:nc) [mol frac]
121
                this is useful for mixtures of a predefined composition, e.g.
122
                refrigerant blends such as R410A
123
        following inputs have meaning only if hrf = 'OTH'
124
            h0--reference state enthalpy at t0,p0 {icomp} [J/mol]
125
            s0--reference state entropy at t0,p0 {icomp} [J/mol-K]
126
            t0--reference state temperature [K]
127
                t0 = -1 indicates saturated liquid at normal boiling point
128
                    (bubble point for a mixture)
129
            p0--reference state pressure [kPa]
130
                p0 = -1 indicates saturated liquid at t0 {and icomp}
131
                p0 = -2 indicates saturated vapor at t0 {and icomp}
132

133
    setmod parameters:
134
    setmod(htype='NBS', hmix='NBS', *hcomp):
135
    inputs 'in string format':
136
        htype - flag indicating which models are to be set [character*3]:
137
            'EOS':  equation of state for thermodynamic properties
138
            'ETA':  viscosity
139
            'TCX':  thermal conductivity
140
            'STN':  surface tension
141
            'NBS':  reset all of the above model types and all subsidiary
142
                component models to 'NBS'; values of hmix and hcomp are ignored
143
        hmix--mixture model to use for the property specified in htype
144
            [character*3]:
145
            ignored if number of components = 1
146
            some allowable choices for hmix:
147
                'NBS':  use NIST recommendation for specified fluid/mixture
148
                'HMX':  mixture Helmholtz model for thermodynamic properties
149
                'ECS':  extended corresponding states for viscosity or th cond
150
                'STX':  surface tension mixture model
151
        hcomp--component model(s) to use for property specified in htype
152
            [array (1..nc) of character*3]:
153
                'NBS':  NIST recommendation for specified fluid/mixture
154
            some allowable choices for an equation of state:
155
                'FEQ':  Helmholtz free energy model
156
                'BWR':  pure fluid modified Benedict-Webb-Rubin (MBWR)
157
                'ECS':  pure fluid thermo extended corresponding states
158
            some allowable choices for viscosity:
159
                'ECS':  extended corresponding states (all fluids)
160
                'VS1':  the 'composite' model for R134a, R152a, NH3, etc.
161
                'VS2':  Younglove-Ely model for hydrocarbons
162
                'VS4':  Generalized friction theory of Quinones-Cisneros and
163
                    Deiters
164
                'VS5':  Chung et al. (1988) predictive model
165
            some allowable choices for thermal conductivity:
166
                'ECS':  extended corresponding states (all fluids)
167
                'TC1':  the 'composite' model for R134a, R152a, etc.
168
                'TC2':  Younglove-Ely model for hydrocarbons
169
                'TC5':  Chung et al. (1988) predictive model
170
            some allowable choices for surface tension:
171
                'ST1':  surface tension as f(tau); tau = 1 - T/Tc
172

173
    setktv parameters
174
    setktv(icomp, jcomp, hmodij, fij=([0] * _nmxpar), hfmix='HMX.BNC'):
175
        icomp--component
176
        jcomp--component j
177
        hmodij--mixing rule for the binary pair i,j [character*3] e.g.:
178
            'LJ1' (Lemmon-Jacobsen model)
179
            'LM1' (modified Lemmon-Jacobsen model) or
180
            'LIN' (linear mixing rules)
181
            'RST' indicates reset all pairs to values from original call to
182
                SETUP (i.e. those read from file) [all other inputs are
183
                ignored]
184
        fij--binary mixture parameters [array of dimension nmxpar; currently
185
            nmxpar is set to 6] the parameters will vary depending on hmodij;
186
            for example, for the Lemmon-Jacobsen model
187
                (LJ1):
188
                    fij(1) = zeta
189
                    fij(2) = xi
190
                    fij(3) = Fpq
191
                    fij(4) = beta
192
                    fij(5) = gamma
193
                    fij(6) = 'not used'
194
        hfmix--file name [character*255] containing generalized parameters
195
            for the binary mixture model; this will usually be the same as the
196
            corresponding input to SETUP (e.g.,':fluids:HMX.BNC')
197
    """
198
    kwargs = {"ids": [],
1✔
199
              "fraccionMolar": [],
200
              "fraccionMasica": [],
201
              "caudalUnitarioMolar": [],
202
              "caudalUnitarioMasico": [],
203

204
              "T": 0.0,
205
              "P": 0.0,
206
              "x": None,
207
              "Q": None,
208
              "rho": 0.0,
209
              "D": 0.0,
210
              "H": 0.0,
211
              "S": 0.0,
212
              "u": 0.0,
213
              "E": 0.0,
214

215
              # Configuration parameters
216
              "preos": False,
217
              "aga": False,
218
              "gerg": False,
219

220
              "hrf": "DEF",
221
              "ixflag": 1,
222
              "x0": [1],
223
              "h0": 0,
224
              "s0": 0,
225
              "t0": 273,
226
              "p0": 1e5,
227

228
              "htype": "NBS",
229
              "hmix": "NBS",
230
              "hcomp": "",
231
              # setktv don't implemented
232
              }
233

234
    @property
1✔
235
    def calculable(self):
1✔
236
        """Check in the class is fully defined. The correct definition require
237
        two parts:
238
        * Thermodynamics definition: whatever pair properties between T, P,
239
            h, s, v, rho, x
240
        * Compound definition: Ids for compound identification, and in
241
            multicomponent defintion any kind of mixture definition
242
        """
243
        # Check mix state
244
        self._multicomponent = False
×
245
        if len(self.kwargs["ids"]) > 1:
×
246
            self._multicomponent = True
×
247

248
        # Check supported fluid
UNCOV
249
        REFPROP_available = True
×
250
        for id in self.kwargs["ids"]:
×
251

252
            if id not in __all__ and id not in noIds:
×
253
                REFPROP_available = False
×
254
                if not REFPROP_available:
×
255
                    raise ValueError
×
256

257
        # Mix definition
258
        self._mix = 0
×
UNCOV
259
        if len(self.kwargs["fraccionMolar"]) == len(self.kwargs["ids"]):
×
260
            self._mix = 1
×
UNCOV
261
        elif len(self.kwargs["fraccionMasica"]) == len(self.kwargs["ids"]):
×
UNCOV
262
            self._mix = 2
×
263
        elif len(self.kwargs["caudalUnitarioMolar"]) == \
×
264
                len(self.kwargs["ids"]):
265
            self._mix = 3
×
UNCOV
266
        elif len(self.kwargs["caudalUnitarioMasico"]) == \
×
267
                len(self.kwargs["ids"]):
UNCOV
268
            self._mix = 4
×
269

270
        # Check correct fluid definition
UNCOV
271
        if self._multicomponent:
×
272
            if self.kwargs["ids"] and self._mix:
×
273
                self._definition = True
×
274
            else:
275
                self._definition = False
×
276
        else:
277
            self._definition = True
×
278

279
        # Update the kwargs with the special refprop namespace
280
        if self.kwargs["x"] != RefProp.kwargs["x"]:
×
281
            self.kwargs["Q"] = self.kwargs["x"]
×
UNCOV
282
        if self.kwargs["rho"] != RefProp.kwargs["rho"]:
×
283
            self.kwargs["D"] = self.kwargs["rho"]
×
UNCOV
284
        if self.kwargs["u"] != RefProp.kwargs["u"]:
×
285
            self.kwargs["E"] = self.kwargs["u"]
×
286

287
        # Check thermo definition
UNCOV
288
        self._thermo = ""
×
UNCOV
289
        for def_ in ["TP", "TQ", "PQ", "TD", "PD", "PH", "PS", "HS", "TH",
×
290
                     "TS", "TE", "PE", "ES", "DH", "DS", "DE"]:
UNCOV
291
            if self.kwargs[def_[0]] != RefProp.kwargs[def_[0]] and \
×
292
                    self.kwargs[def_[1]] != RefProp.kwargs[def_[1]]:
293
                self._thermo = def_
×
294

UNCOV
295
        return self._definition and self._thermo
×
296

297
    def args(self):
1✔
298
        x = self._x()
×
299
        # Convert to float because unit subclass raise InputError
300
        var1 = float(self.kwargs[self._thermo[0]])
×
301
        var2 = float(self.kwargs[self._thermo[1]])
×
302

303
        # unit conversion to refprop accepted units
304
        # P in kPa, U,H in kJ/kmol, S in kJ/kmolK
305
        if self._thermo[0] == "P":
×
306
            var1 /= 1000.
×
307
        elif self._thermo[0] in ("E", "H", "S"):
×
308
            var1 /= 1000. / self.M
×
309
        elif self._thermo[0] == "D":
×
UNCOV
310
            var1 /= self.M
×
311

UNCOV
312
        if self._thermo[1] == "P":
×
UNCOV
313
            var2 /= 1000.
×
314
        elif self._thermo[1] in ("E", "H", "S"):
×
315
            var2 /= 1000. / self.M
×
316
        elif self._thermo[1] == "D":
×
317
            var2 /= self.M
×
318

319
        return self._thermo, var1, var2, x
×
320

321
    def _name(self):
1✔
UNCOV
322
        name = []
×
323
        for fld in self.kwargs["ids"]:
×
324
            if fld in __all__:
×
325
                name.append(__all__[fld])
×
326
            elif fld in noIds:
×
327
                name.append(fld)
×
328
        return name
×
329

330
    def _x(self):
1✔
331
        if self._mix == 1:
×
332
            x = self.kwargs["fraccionMolar"]
×
UNCOV
333
        elif self._mix == 2:
×
334
            x = refprop.xmole(self.kwargs["fraccionMasica"])["x"]
×
335
        elif self._mix == 3:
×
UNCOV
336
            kw = mix_unitmolarflow(self.kwargs["caudalUnitarioMolar"])
×
UNCOV
337
            x = kw["fraccionMolar"]
×
UNCOV
338
        elif self._mix == 3:
×
UNCOV
339
            kw = mix_unitmassflow(self.kwargs["caudalUnitarioMasico"])
×
UNCOV
340
            x = kw["fraccionMolar"]
×
341
        else:
342
            x = [1]
×
UNCOV
343
        return x
×
344

345
    def _fixed(self):
1✔
346
        """Calculate fixed properties with the chemical compound ids specified,
347
        valid only for one component"""
348

349
        x = self._x()
×
350
        fluido = self._name()
×
351

352
        refprop.setup("def", fluido)
×
353

354
        info = refprop.info()
×
355
        self.M = unidades.Dimensionless(info["wmm"])
×
356
        self.Tt = unidades.Temperature(info["ttrp"])
×
357
        self.Tb = unidades.Temperature(info["tnbpt"])
×
UNCOV
358
        self.Tc = unidades.Temperature(info["tcrit"])
×
359

360
        self.R = unidades.SpecificHeat(info["Rgas"]/self.M)
×
361
        self.f_accent = unidades.Dimensionless(info["acf"])
×
UNCOV
362
        self.momentoDipolar = unidades.DipoleMoment(info["dip"], "Debye")
×
UNCOV
363
        self.rhoc = unidades.Density(info["Dcrit"]*self.M)
×
UNCOV
364
        self.zc = unidades.Dimensionless(info["zcrit"])
×
UNCOV
365
        self.Pc = unidades.Pressure(self.R*self.Tc*self.rhoc*self.zc, "kPa")
×
366

367
        name = refprop.name()
×
368
        self.name = name["hname"]
×
369
        self.CAS = name["hcas"]
×
370

371
    def cleanOldValues(self, **kwargs):
1✔
372
        """Convert alternative input parameters"""
373
        # Alternative rho input
374
        if "rhom" in kwargs:
×
UNCOV
375
            kwargs["rho"] = kwargs["rhom"]*self.M
×
376
            del kwargs["rhom"]
×
377
        elif kwargs.get("v", 0):
×
378
            kwargs["rho"] = 1./kwargs["v"]
×
UNCOV
379
            del kwargs["v"]
×
380
        elif kwargs.get("vm", 0):
×
381
            kwargs["rho"] = self.M/kwargs["vm"]
×
382
            del kwargs["vm"]
×
383

UNCOV
384
        if kwargs.get("s", 0):
×
UNCOV
385
            kwargs["S"] = kwargs["s"]
×
386
            del kwargs["s"]
×
387

388
        if kwargs.get("h", 0):
×
UNCOV
389
            kwargs["H"] = kwargs["h"]
×
UNCOV
390
            del kwargs["h"]
×
391
        self.kwargs.update(kwargs)
×
392

393
    def cleanOldKwargs(self):
1✔
394
        for var in ["T", "P", "Q", "D", "H", "S", "E"]:
×
395
            if var not in self._thermo:
×
396
                self.kwargs[var] = RefProp.kwargs[var]
×
397

398
    def calculo(self):
1✔
UNCOV
399
        try:
×
UNCOV
400
            self._calculo()
×
UNCOV
401
        except refprop.RefpropdllError as e:
×
UNCOV
402
            self.status = 5
×
UNCOV
403
            self.msg = str(e)
×
UNCOV
404
        except refprop.RefpropdllWarning as e:
×
405
            self.status = 5
×
406
            self.msg = str(e)
×
407

408
    def _initialization(self):
1✔
409
        # TODO: Add configuration section to Preferences
410
        # preos = Preferences.getboolean("refProp", "preos")
411
        # aga = Preferences.getboolean("refProp", "aga")
412
        # gerg = Preferences.getboolean("refProp", "gerg")
413
        preos = self.kwargs["preos"]
×
414
        aga = self.kwargs["aga"]
×
415
        gerg = self.kwargs["gerg"]
×
416

417
        fluido = self._name()
×
418

419
        kwmod = [self.kwargs[k] for k in ('htype', 'hmix', 'hcomp')]
×
420
        refprop.setmod(*kwmod)
×
421
        if gerg:
×
UNCOV
422
            refprop.gerg04(ixflag=1)
×
423
        refprop.setup("def", fluido)
×
424
        # refprop.setktv()
UNCOV
425
        if preos:
×
426
            refprop.preos(ixflag=2)
×
UNCOV
427
        elif aga:
×
428
            refprop.setaga()
×
429
        kwref = {k: self.kwargs[k] for k in (
×
430
            'hrf', 'ixflag', 'x0', 'h0', 's0', 't0', 'p0')}
431
        refprop.setref(**kwref)
×
432

433
    def _calculo(self):
1✔
434
        self._initialization()
×
435

436
        x = self._x()
×
437
        m = refprop.wmol(x)["wmix"]
×
UNCOV
438
        self.M = unidades.Dimensionless(m)
×
UNCOV
439
        crit = refprop.critp(x)
×
440
        self.Pc = unidades.Pressure(crit["pcrit"], "kPa")
×
441
        self.Tc = unidades.Temperature(crit["tcrit"])
×
442
        self.rhoc = unidades.Density(crit["Dcrit"]*self.M)
×
443

444
        args = self.args()
×
445
        flash = refprop.flsh(*args)
×
446

447
        # check if ['q'] in fld
UNCOV
448
        if 'q' in flash.keys():
×
449
            x = flash['q']
×
UNCOV
450
        elif 'h' in flash.keys():
×
451
            x = refprop.flsh('ph', flash['p'], flash['h'], flash['x'])['q']
×
452
        elif 's' in flash.keys():
×
453
            x = refprop.flsh('ps', flash['p'], flash['s'], flash['x'])['q']
×
454
        if 0 < x < 1:
×
455
            region = 4
×
456
        else:
457
            region = 1
×
458

459
        if x < 0:
×
460
            x = 0
×
461
        elif x > 1:
×
462
            x = 1
×
UNCOV
463
        self.x = unidades.Dimensionless(x)
×
UNCOV
464
        self.T = unidades.Temperature(flash["t"])
×
465
        self.P = unidades.Pressure(flash["p"], "kPa")
×
466
        self.Tr = unidades.Dimensionless(self.T/self.Tc)
×
467
        self.Pr = unidades.Dimensionless(self.P/self.Pc)
×
468
        self.rho = unidades.Density(flash["D"]*self.M)
×
469
        self.v = unidades.SpecificVolume(1./self.rho)
×
UNCOV
470
        self.phase = self.getphase(Tc=self.Tc, Pc=self.Pc, T=self.T, P=self.Pc,
×
471
                                   x=self.x, region=region)
472

473
        if flash["nc"] == 1:
×
474
            name = refprop.name(flash["nc"])
×
475
            self.name = name["hname"]
×
476
            self.synonim = name["hn80"]
×
477
            self.CAS = name["hcas"]
×
478

UNCOV
479
            info = refprop.info(flash["nc"])
×
480
            self.R = unidades.SpecificHeat(info["Rgas"]/self.M)
×
UNCOV
481
            self.Tt = unidades.Temperature(info["ttrp"])
×
482
            self.Tb = unidades.Temperature(info["tnbpt"])
×
483
            self.f_accent = unidades.Dimensionless(info["acf"])
×
484
            self.momentoDipolar = unidades.DipoleMoment(info["dip"], "Debye")
×
UNCOV
485
            self._doc = {}
×
486
            for htype in ['EOS', 'CP0', 'ETA', 'VSK', 'TCX', 'TKK', 'STN',
×
487
                          'DE ', 'MLT', 'SBL', 'PS ', 'DL ', 'DV ']:
488
                self._doc[htype] = refprop.getmod(flash["nc"], htype)["hcite"]
×
489
        else:
490
            self.name = ""
×
491
            self.synonim = ""
×
492
            self.CAS = ""
×
493

494
            rmix = refprop.rmix2(flash["x"])
×
UNCOV
495
            self.R = unidades.SpecificHeat(rmix["Rgas"]/self.M)
×
496
            self.Tt = unidades.Temperature(None)
×
497
            self.Tb = unidades.Temperature(None)
×
498
            self.f_accent = unidades.Dimensionless(None)
×
UNCOV
499
            self.momentoDipolar = unidades.DipoleMoment(None)
×
500
            self._doc = {}
×
501

502
        self._cp0(flash)
×
503

UNCOV
504
        self.Liquido = ThermoRefProp()
×
505
        self.Gas = ThermoRefProp()
×
506
        if self.x == 0.:
×
507
            # liquid phase
UNCOV
508
            self.fill(self.Liquido, flash["t"], flash["D"], flash["x"])
×
UNCOV
509
            self.fill(self, flash["t"], flash["D"], flash["x"])
×
510
            self.fillNone(self.Gas)
×
511
        elif self.x == 1.:
×
512
            # vapor phase
UNCOV
513
            self.fill(self.Gas, flash["t"], flash["D"], flash["x"])
×
514
            self.fill(self, flash["t"], flash["D"], flash["x"])
×
515
            self.fillNone(self.Liquido)
×
516
        else:
517
            # Two phase
518
            self.fillNone(self)
×
519
            self.fill(self.Liquido, flash["t"], flash["Dliq"], flash["xliq"])
×
520
            self.fill(self.Gas, flash["t"], flash["Dvap"], flash["xvap"])
×
521

UNCOV
522
            self.v = unidades.SpecificVolume(x*self.Gas.v+(1-x)*self.Liquido.v)
×
523
            self.rho = unidades.Density(1./self.v)
×
524

525
            self.u = unidades.Enthalpy(flash["e"]/self.M, "Jg")
×
526
            self.h = unidades.Enthalpy(flash["h"]/self.M, "Jg")
×
527
            self.s = unidades.SpecificHeat(flash["s"]/self.M, "JgK")
×
528
            self.a = unidades.Enthalpy(self.u-self.T*self.s)
×
UNCOV
529
            self.g = unidades.Enthalpy(self.h-self.T*self.s)
×
530

531
            self.rhoM = unidades.MolarDensity(self.rho/self.M)
×
UNCOV
532
            self.hM = unidades.MolarEnthalpy(self.h*self.M)
×
533
            self.sM = unidades.MolarSpecificHeat(self.s*self.M)
×
UNCOV
534
            self.uM = unidades.MolarEnthalpy(self.u*self.M)
×
535
            self.aM = unidades.MolarEnthalpy(self.a*self.M)
×
UNCOV
536
            self.gM = unidades.MolarEnthalpy(self.g*self.M)
×
537

538
        if self.x < 1 and self.T <= self.Tc:
×
539
            surten = refprop.surten(flash["t"], flash["Dliq"], flash["Dvap"],
×
540
                                    flash["xliq"], flash["xvap"])
541
            self.sigma = unidades.Tension(surten["sigma"])
×
542
        else:
UNCOV
543
            self.sigma = unidades.Tension(None)
×
544

545
        if 0 < self.x < 1:
×
546
            self.Hvap = unidades.Enthalpy(self.Gas.h-self.Liquido.h)
×
547
            self.Svap = unidades.SpecificHeat(self.Gas.s-self.Liquido.s)
×
UNCOV
548
            self.K = []
×
UNCOV
549
            for x, y in zip(self.Liquido.fraccion, self.Gas.fraccion):
×
550
                self.K.append(unidades.Dimensionless(y/x))
×
551
        else:
552
            self.Hvap = unidades.Enthalpy(None)
×
553
            self.Svap = unidades.SpecificHeat(None)
×
554
            self.K = [unidades.Dimensionless(1)]*flash["nc"]
×
555
        self.invT = unidades.InvTemperature(-1/self.T)
×
556

557
        # NOT supported on Windows
UNCOV
558
        if sys.platform != "win32":
×
559
            excess = refprop.excess(flash["t"], flash["D"], flash["x"])
×
560
            self.vE = unidades.Volume(excess["vE"]/self.M)
×
561
            self.uE = unidades.Enthalpy(excess["eE"]/self.M, "Jg")
×
562
            self.hE = unidades.Enthalpy(excess["hE"]/self.M, "Jg")
×
563
            self.sE = unidades.SpecificHeat(excess["sE"]/self.M, "JgK")
×
564
            self.aE = unidades.Enthalpy(excess["aE"]/self.M, "Jg")
×
UNCOV
565
            self.gE = unidades.Enthalpy(excess["gE"]/self.M, "Jg")
×
566
        else:
567
            self.vE = unidades.Volume(0)
×
568
            self.uE = unidades.Enthalpy(0)
×
569
            self.hE = unidades.Enthalpy(0)
×
570
            self.sE = unidades.SpecificHeat(0)
×
571
            self.aE = unidades.Enthalpy(0)
×
572
            self.gE = unidades.Enthalpy(0)
×
573

574
        self.csat = []
×
UNCOV
575
        self.dpdt_sat = []
×
576
        self.cv2p = []
×
577
        if self.Tt <= flash["t"] <= self.Tc:
×
578
            for i in range(1, flash["nc"]+1):
×
UNCOV
579
                dat = refprop.dptsatk(i, flash["t"], kph=2)
×
UNCOV
580
                cs = unidades.SpecificHeat(dat["csat"]/self.M, "JgK")
×
UNCOV
581
                self.csat.append(cs)
×
582
                self.dpdt_sat.append(
×
583
                    unidades.PressureTemperature(dat["dpdt"], "kPaK"))
584
                cv2 = refprop.cv2pk(i, flash["t"], flash["D"])
×
585
                cv = unidades.SpecificHeat(cv2["cv2p"]/self.M, "JgK")
×
586
                self.cv2p.append(cv)
×
587

588
    def _cp0(self, flash):
1✔
589
        "Set ideal properties to state"""
590
        cp0 = refprop.therm0(flash["t"], flash["D"], flash["x"])
×
591
        self.v0 = unidades.SpecificVolume(self.R*self.T/self.P.kPa)
×
592
        self.rho0 = unidades.Density(1/self.v0)
×
593
        self.P0 = unidades.Pressure(cp0["p"], "kPa")
×
UNCOV
594
        self.P_Pideal = unidades.Pressure(self.P-self.P0)
×
595

596
        self.h0 = unidades.Enthalpy(cp0["h"]/self.M, "kJkg")
×
597
        self.u0 = unidades.Enthalpy(cp0["e"]/self.M, "kJkg")
×
598
        self.s0 = unidades.SpecificHeat(cp0["s"]/self.M, "kJkgK")
×
599
        self.a0 = unidades.Enthalpy(cp0["A"]/self.M, "kJkg")
×
UNCOV
600
        self.g0 = unidades.Enthalpy(cp0["G"]/self.M, "kJkg")
×
601
        self.w0 = unidades.Speed(cp0["w"])
×
602

603
        cp0 = refprop.therm0(float(self.T), self.rho0/self.M, flash["x"])
×
604
        self.cp0 = unidades.SpecificHeat(cp0["cp"]/self.M, "kJkgK")
×
605
        self.cv0 = unidades.SpecificHeat(cp0["cv"]/self.M, "kJkgK")
×
606
        self.cp0_cv = unidades.Dimensionless(self.cp0/self.cv0)
×
607
        self.gamma0 = self.cp0_cv
×
608

UNCOV
609
        self.rhoM0 = unidades.MolarDensity(self.rho0/self.M)
×
UNCOV
610
        self.hM0 = unidades.MolarEnthalpy(self.h0*self.M)
×
611
        self.uM0 = unidades.MolarEnthalpy(self.u0*self.M)
×
612
        self.sM0 = unidades.MolarSpecificHeat(self.s0*self.M)
×
613
        self.aM0 = unidades.MolarEnthalpy(self.a0*self.M)
×
614
        self.gM0 = unidades.MolarEnthalpy(self.g0*self.M)
×
615
        self.cpM0 = unidades.MolarSpecificHeat(self.cp0*self.M)
×
UNCOV
616
        self.cvM0 = unidades.MolarSpecificHeat(self.cv0*self.M)
×
617

618
    def fill(self, fase, T, rho, x):
1✔
619
        if sum(x) != 1:
×
620
            x = [round(xi, 10) for xi in x]
×
621
        mol = refprop.wmol(x)
×
UNCOV
622
        thermo = refprop.therm2(T, rho, x)
×
623
        thermo3 = refprop.therm3(T, rho, x)
×
624

625
        fase._bool = True
×
626
        fase.M = unidades.Dimensionless(mol["wmix"])
×
627
        fase.rho = unidades.Density(rho*fase.M)
×
UNCOV
628
        fase.v = unidades.SpecificVolume(1./fase.rho)
×
629
        fase.Z = unidades.Dimensionless(thermo["Z"])
×
630

631
        fase.u = unidades.Enthalpy(thermo["e"]/fase.M, "Jg")
×
632
        fase.h = unidades.Enthalpy(thermo["h"]/fase.M, "Jg")
×
633
        fase.s = unidades.SpecificHeat(thermo["s"]/fase.M, "JgK")
×
UNCOV
634
        fase.a = unidades.Enthalpy(thermo["A"]/fase.M, "Jg")
×
635
        fase.g = unidades.Enthalpy(thermo["G"]/fase.M, "Jg")
×
636

637
        fase.cv = unidades.SpecificHeat(thermo["cv"]/fase.M, "JgK")
×
638
        fase.cp = unidades.SpecificHeat(thermo["cp"]/fase.M, "JgK")
×
639
        fase.cp_cv = unidades.Dimensionless(fase.cp/fase.cv)
×
640
        fase.gamma = fase.cp_cv
×
641
        fase.w = unidades.Speed(thermo["w"])
×
642

UNCOV
643
        fase.rhoM = unidades.MolarDensity(fase.rho/self.M)
×
644
        fase.hM = unidades.MolarEnthalpy(fase.h*self.M)
×
645
        fase.sM = unidades.MolarSpecificHeat(fase.s*self.M)
×
646
        fase.uM = unidades.MolarEnthalpy(fase.u*self.M)
×
647
        fase.aM = unidades.MolarEnthalpy(fase.a*self.M)
×
648
        fase.gM = unidades.MolarEnthalpy(fase.g*self.M)
×
649
        fase.cvM = unidades.MolarSpecificHeat(fase.cv*self.M)
×
650
        fase.cpM = unidades.MolarSpecificHeat(fase.cp*self.M)
×
651

652
        residual = refprop.residual(T, rho, x)
×
UNCOV
653
        fase.pr = unidades.Pressure(residual["pr"], "kPa")
×
654
        fase.ur = unidades.Enthalpy(residual["er"]/fase.M, "Jg")
×
655
        fase.hr = unidades.Enthalpy(residual["hr"]/fase.M, "Jg")
×
656
        fase.sr = unidades.SpecificHeat(residual["sr"]/fase.M, "JgK")
×
657
        fase.ar = unidades.Enthalpy(residual["Ar"]/fase.M, "Jg")
×
658
        fase.gr = unidades.Enthalpy(residual["Gr"]/fase.M, "Jg")
×
UNCOV
659
        fase.cvr = unidades.SpecificHeat(residual["cvr"]/fase.M, "JgK")
×
660
        fase.cpr = unidades.SpecificHeat(residual["cpr"]/fase.M, "JgK")
×
661

UNCOV
662
        fase.alfav = unidades.InvTemperature(thermo["beta"])
×
663
        fase.kappa = unidades.InvPressure(thermo["xkappa"], "kPa")
×
UNCOV
664
        fase.kappas = unidades.InvPressure(thermo3["betas"], "kPa")
×
UNCOV
665
        fase.alfap = unidades.Density(fase.alfav/self.P/fase.kappa)
×
666
        fase.deltat = unidades.EnthalpyPressure(
×
667
            thermo3["thrott"]/fase.M, "kJkgkPa")
668
        fase.joule = unidades.TemperaturePressure(thermo["hjt"], "KkPa")
×
669
        fase.betas = unidades.TemperaturePressure(
×
670
            self.derivative("T", "P", "s", fase))
671
        fase.betap = unidades.Density(
×
672
            -1/self.P*self.derivative("P", "v", "T", fase))
673

674
        fase.Kt = unidades.Pressure(thermo3["xkkt"], "kPa")
×
UNCOV
675
        fase.Ks = unidades.Pressure(thermo3["bs"], "kPa")
×
676
        fase.kt = unidades.Dimensionless(thermo3["xkt"])
×
UNCOV
677
        fase.ks = unidades.Dimensionless(thermo3["xisenk"])
×
678

UNCOV
679
        dh = refprop.dhd1(T, rho, x)
×
680
        fase.dhdT_rho = unidades.SpecificHeat(dh["dhdt_D"]/fase.M, "kJkgK")
×
UNCOV
681
        fase.dhdT_P = unidades.SpecificHeat(dh["dhdt_p"]/fase.M, "kJkgK")
×
UNCOV
682
        fase.dhdP_T = unidades.EnthalpyPressure(dh["dhdp_t"]/fase.M, "kJkgkPa")
×
683
        # dhdtp_D : fix in library
684
        fase.dhdP_rho = unidades.EnthalpyPressure(
×
685
            dh["dhdtp_D"]/fase.M, "kJkgkPa")
UNCOV
686
        fase.dhdrho_T = unidades.EnthalpyDensity(
×
687
            dh["dhdD_t"]/fase.M**2, "kJkgkgm3")
688
        fase.dhdrho_P = unidades.EnthalpyDensity(
×
689
            dh["dhdD_p"]/fase.M**2, "kJkgkgm3")
690

691
        fase.dpdT_rho = unidades.PressureTemperature(thermo["dpdt"], "kPaK")
×
692
        fase.dpdrho_T = unidades.PressureDensity(
×
693
            thermo["dpdD"]/fase.M, "kPakgm3")
694
        # TODO: Add unit for derivative d^2p/dD^2 [kPa-L^2/mol^2]
695
        # MPa·m⁶/kg²
696
        fase.d2pdrho2 = unidades.Dimensionless(thermo["d2pdD2"]/fase.M**2/1000)
×
697
        fase.drhodP_T = unidades.DensityPressure(
×
698
            thermo["dDdp"]*fase.M, "kgm3kPa")
699
        fase.drhodT_P = unidades.DensityTemperature(thermo["dDdt"]*fase.M)
×
700
        fase.Gruneisen = unidades.Dimensionless(fase.v/fase.cv*fase.dpdT_rho)
×
701

702
        fase.Z_rho = unidades.SpecificVolume((fase.Z-1)/fase.rho)
×
703
        fase.IntP = unidades.Pressure(thermo3["pint"], "kPa")
×
704
        fase.hInput = unidades.Enthalpy(thermo3["spht"]/fase.M, "kJkg")
×
705
        fase.invT = unidades.InvTemperature(-1/self.T)
×
706

707
        fpv = refprop.fpv(T, rho, self.P.kPa, x)["Fpv"]
×
UNCOV
708
        fase.fpv = unidades.Dimensionless(fpv)
×
709

710
        chempot = refprop.chempot(T, rho, x)["u"]
×
711
        fase.chempot = [unidades.Enthalpy(c/fase.M) for c in chempot]
×
712
        fi = refprop.fugcof(T, rho, x)["f"]
×
UNCOV
713
        fase.fi = [unidades.Dimensionless(f) for f in fi]
×
UNCOV
714
        f = refprop.fgcty(T, rho, x)["f"]
×
715
        fase.f = [unidades.Pressure(f_i, "kPa") for f_i in f]
×
716

717
        b = refprop.virb(T, x)["b"]
×
UNCOV
718
        fase.virialB = unidades.SpecificVolume(b/self.M)
×
719
        c = refprop.virc(T, x)["c"]
×
UNCOV
720
        fase.virialC = unidades.SpecificVolume_square(c/self.M**2)
×
721

722
        # viriald don't supported for windows
723
        if sys.platform != "win32":
×
724
            d = refprop.vird(T, x)["d"]
×
725
            fase.virialD = unidades.Dimensionless(d/self.M**3)
×
726
        else:
727
            fase.virialD = unidades.Dimensionless(0)
×
728

729
        ba = refprop.virba(T, x)["ba"]
×
730
        fase.virialBa = unidades.SpecificVolume(ba/self.M)
×
UNCOV
731
        ca = refprop.virca(T, x)["ca"]
×
732
        fase.virialCa = unidades.SpecificVolume_square(ca/self.M**2)
×
733
        dcdt = refprop.dcdt(T, x)["dct"]
×
734
        fase.dCdt = unidades.Dimensionless(dcdt/self.M**2)
×
735
        dcdt2 = refprop.dcdt2(T, x)["dct2"]
×
736
        fase.dCdt2 = unidades.Dimensionless(dcdt2/self.M**2)
×
737
        dbdt = refprop.dbdt(T, x)["dbt"]
×
738
        fase.dBdt = unidades.Dimensionless(dbdt/self.M)
×
739

740
        b12 = refprop.b12(T, x)["b"]
×
741
        fase.b12 = unidades.SpecificVolume(b12*fase.M)
×
742
        try:
×
UNCOV
743
            cstar = refprop.cstar(T, self.P.kPa, 0, x)["cs"]
×
744
            fase.cstar = unidades.Dimensionless(cstar)
×
745
        except refprop.RefpropdllError:
×
746
            fase.cstar = unidades.Dimensionless(None)
×
747

748
        fase.fraccion = [unidades.Dimensionless(xi) for xi in x]
×
749
        xg = refprop.xmass(x)["xkg"]
×
750
        fase.fraccion_masica = [unidades.Dimensionless(xi) for xi in xg]
×
751

752
        try:
×
753
            transport = refprop.trnprp(T, rho, x)
×
754
            fase.mu = unidades.Viscosity(transport["eta"], "muPas")
×
755
            fase.nu = unidades.Diffusivity(fase.mu/fase.rho)
×
756
            fase.k = unidades.ThermalConductivity(transport["tcx"])
×
UNCOV
757
            fase.alfa = unidades.Diffusivity(fase.k/fase.rho/fase.cp)
×
758
            fase.Prandt = unidades.Dimensionless(fase.mu*fase.cp/fase.k)
×
759
        except refprop.RefpropdllError:
×
UNCOV
760
            fase.mu = unidades.Viscosity(None)
×
UNCOV
761
            fase.nu = unidades.Diffusivity(None)
×
UNCOV
762
            fase.k = unidades.ThermalConductivity(None)
×
UNCOV
763
            fase.alfa = unidades.Diffusivity(None)
×
UNCOV
764
            fase.Prandt = unidades.Dimensionless(None)
×
765

UNCOV
766
        dielec = refprop.dielec(T, rho, x)
×
UNCOV
767
        fase.epsilon = unidades.Dimensionless(dielec["de"])
×
768

769
    def _Melting_Pressure(self, T, x):
1✔
770
        r"""Calculate the melting pressure.
771

772
        Parameters
773
        ----------
774
        T : float
775
            Temperature, [K]
776
        x : list
777
            Molar fraction composition, [-]
778

779
        Returns
780
        -------
781
        P : float
782
            Melting pressure, [Pa]
783
        """
UNCOV
784
        self._initialization()
×
785

UNCOV
786
        P = refprop.meltt(T, x)
×
UNCOV
787
        return unidades.Pressure(P["p"], "kPa")
×
788

789
    def _Sublimation_Pressure(self, T, x):
1✔
790
        r"""Calculate the sublimation pressure.
791

792
        Parameters
793
        ----------
794
        T : float
795
            Temperature, [K]
796
        x : list
797
            Molar fraction composition, [-]
798

799
        Returns
800
        -------
801
        P : float
802
            Sublimation pressure, [Pa]
803
        """
UNCOV
804
        self._initialization()
×
805

UNCOV
806
        P = refprop.sublt(T, x)
×
UNCOV
807
        return unidades.Pressure(P["p"], "kPa")
×
808

809

810
if __name__ == '__main__':
1✔
811
    # fluido = RefProp(ids=[140], T=300, P=1e6,)
812
    # fluido2 = RefProp(ids=[140], T=300, P=1e6, preos=True)
813
    # print(fluido.rho, fluido2.rho)
814
    # from lib.mEoS import Acetone
815
    # fluido = Acetone(T=300, P=1e6)
816
    # from pprint import pprint
817
    # pprint(fluido._Helmholtz(fluido.Tc/fluido.T, fluido.rho/fluido.rhoc))
818
    # pprint(fluido._PengRobinson(fluido.rho, fluido.T))
819
    # fluido2 = Acetone(T=300, P=1e6, eq="PR")
820
    # print(fluido.rho, fluido2.rho)
821

822
    # fluido = RefProp(ids=[47], T=100, P=6e4, htype="EOS", hcomp="BWR")
823
    # print(fluido.rho, fluido.cpM.JmolK)
824

825

826

827
    # See fortran/Manual.txt and fortran/Prop_sub.for file for explanation of refprop functionality
828

829
    # Code for advanced thermal test
830
    # from lib.mEoS.H2O import H2O
831
    # from lib.coolProp import CoolProp
832
    # from lib.iapws97 import IAPWS97
833
    # from lib.freeSteam import Freesteam
834

835
    # P = 2e4
836
    # T = 300
837

838
    # # Fluid definition, r refprop used as reference fluid, choose a m fluid to
839
    # # test against reference
840
    # r = RefProp(ids=[62], T=T, P=P)
841

842
    # # m = H2O(T=T, P=P)
843
    # # ierr = 1e-5
844
    # m = CoolProp(ids=[62], fraccionMolar=[1], T=T, P=P)
845
    # ierr = 1e-5
846
    # # m = IAPWS97(T=T, P=P)
847
    # # ierr = 1
848
    # # m = Freesteam(T=T, P=P)
849
    # # ierr = 1
850

851
    # for prop, key, unit in m.properties():
852
        # if key == "sigma":
853
            # try:
854
                # error = abs(r.Liquido.__getattribute__(key)-m.Liquido.__getattribute__(key))/r.Liquido.__getattribute__(key)*100
855
                # if error > ierr:
856
                    # msg = "ERROR %0.5g%s" % (error, "%")
857
                    # print("%s: %0.9g %0.9g %s" % (key, r.Liquido.__getattribute__(key), m.Liquido.__getattribute__(key), msg))
858
            # except ZeroDivisionError:
859
                # print(key, "no implementado")
860
        # elif key == "n":
861
            # pass
862
        # elif isinstance(r.__getattribute__(key), list):
863
            # error = 0
864
            # for v1, v2 in zip(r.__getattribute__(key), m.__getattribute__(key)):
865
                # error2 = abs(v1-v2)/v1*100
866
                # if error2 > error:
867
                    # error = error2
868
                # if error > ierr:
869
                    # msg = "ERROR %0.5g%s" % (error, "%")
870
                    # print("%s: " % key, r.__getattribute__(key), m.__getattribute__(key), msg)
871
        # else:
872
            # try:
873
                # error = abs(r.__getattribute__(key)-m.__getattribute__(key))/r.__getattribute__(key)*100
874
                # if error > ierr:
875
                    # msg = "ERROR %0.5g%s" % (error, "%")
876
                    # print("%s: %0.9g %0.9g %s" % (key, r.__getattribute__(key), m.__getattribute__(key), msg))
877
            # except ZeroDivisionError:
878
                # if r.__getattribute__(key) == m.__getattribute__(key):
879
                    # pass
880

881

UNCOV
882
    st = RefProp(ids=[140])
×
UNCOV
883
    p = st._Sublimation_Pressure(178, [1])
×
UNCOV
884
    print(p)
×
UNCOV
885
    from lib.mEoS import H2O
×
UNCOV
886
    st2 = H2O(T=300)
×
UNCOV
887
    p = st2._Sublimation_Pressure(263.16)
×
UNCOV
888
    print(p)
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc