From 3dae0d4a847f91894b37f2480821fbe41344d565 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 16:24:08 -0500 Subject: [PATCH 001/102] Follow scipy deprecation advice (more or less). DeprecationWarning: scipy.exp is deprecated and will be removed in SciPy 2.0.0, use numpy.exp instead DeprecationWarning: scipy.log is deprecated and will be removed in SciPy 2.0.0, use numpy.lib.scimath.log instead --- iapws/iapws95.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 795c37b..117811c 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -15,7 +15,7 @@ import platform import warnings -from scipy import exp, log, ndarray +from numpy import exp, log, ndarray from scipy.optimize import fsolve from .iapws97 import _TSat_P, IAPWS97 From 8c94df06479a7b54a35c1bc63556522b782c1e3b Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 16:27:12 -0500 Subject: [PATCH 002/102] Correct flake8 E117 complaint. ./iapws/iapws08.py:665:13: E117 over-indented --- iapws/iapws08.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iapws/iapws08.py b/iapws/iapws08.py index bd00e47..7b7f650 100644 --- a/iapws/iapws08.py +++ b/iapws/iapws08.py @@ -662,7 +662,7 @@ def _Tension_SeaWater(T, S): if S < 0 or S > 0.131: raise NotImplementedError("Incoming out of bound") else: - raise NotImplementedError("Incoming out of bound") + raise NotImplementedError("Incoming out of bound") sw = _Tension(T) sigma = sw*(1+3.766e-1*S+2.347e-3*S*(T-273.15)) From f2a60632fe4be4532c2b95f2e9d4e7d1cf1c413f Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 16:29:03 -0500 Subject: [PATCH 003/102] Correct flake8 E121 complaints. ./docs/conf.py:243:3: E121 continuation line under-indented for hanging indent ./docs/conf.py:287:3: E121 continuation line under-indented for hanging indent --- docs/conf.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index b5c28d4..bb0a541 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -240,8 +240,8 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'iapws.tex', u'iapws Documentation', - u'Juan José Gómez Romera', 'manual'), + (master_doc, 'iapws.tex', u'iapws Documentation', + u'Juan José Gómez Romera', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of @@ -284,9 +284,9 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'iapws', u'iapws Documentation', - author, 'iapws', 'One line description of project.', - 'Miscellaneous'), + (master_doc, 'iapws', u'iapws Documentation', + author, 'iapws', 'One line description of project.', + 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. From 7df20acb8a5b60e6e4394347ea82168e7b6af9b7 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 16:30:49 -0500 Subject: [PATCH 004/102] Correct flake8 E122 complaints. E122 continuation line missing indentation or outdented --- docs/conf.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index bb0a541..fae2f1e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -223,17 +223,17 @@ # -- Options for LaTeX output --------------------------------------------- latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', + # The paper size ('letterpaper' or 'a4paper'). + #'papersize': 'letterpaper', -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', + # The font size ('10pt', '11pt' or '12pt'). + #'pointsize': '10pt', -# Additional stuff for the LaTeX preamble. -#'preamble': '', + # Additional stuff for the LaTeX preamble. + #'preamble': '', -# Latex figure (float) alignment -#'figure_align': 'htbp', + # Latex figure (float) alignment + #'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples From 4c71bb5e2c44b2a35ab9845f5cbc33b3c7acf0b8 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 16:33:16 -0500 Subject: [PATCH 005/102] Correct flake8 E123 complaints. E123 closing bracket does not match indentation of opening bracket's line --- iapws/__init__.py | 2 +- iapws/iapws97.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/iapws/__init__.py b/iapws/__init__.py index de21f2e..872e6ae 100644 --- a/iapws/__init__.py +++ b/iapws/__init__.py @@ -241,4 +241,4 @@ "Seawater", "ref": "2016", "doi": ""}, - } +} diff --git a/iapws/iapws97.py b/iapws/iapws97.py index 6ac7cff..b0a9316 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -3119,7 +3119,7 @@ def _Backward3x_v_PT(T, P, x): "x": [0.0049, 23, 650, 0.910, 0.988, 1, 1, 1], "y": [0.0031, 22, 650, 0.996, 0.994, 1, 1, 4], "z": [0.0038, 22, 650, 0.993, 0.994, 1, 1, 4], - } + } I = { "a": [-12, -12, -12, -10, -10, -10, -8, -8, -8, -6, -5, -5, -5, -4, -3, From 9674200b5fe50e3e71708365f48b058f7c0a7a36 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 16:35:49 -0500 Subject: [PATCH 006/102] Correct flake8 E126 complaints. E126 continuation line over-indented for hanging indent --- iapws/iapws95.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 117811c..5830198 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -150,7 +150,7 @@ def _phird(tau, delta, coef): g3 = coef.get("gamma3", []) for n, d, t, a, e, b, g in zip(nr3, d3, t3, a3, e3, b3, g3): fird += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - d/delta-2*a*(delta-e)) + d/delta-2*a*(delta-e)) # Non analitic terms nr4 = coef.get("nr4", []) @@ -230,7 +230,7 @@ def _phirt(tau, delta, coef): g3 = coef.get("gamma3", []) for n, d, t, a, e, b, g in zip(nr3, d3, t3, a3, e3, b3, g3): firt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - t/tau-2*b*(tau-g)) + t/tau-2*b*(tau-g)) # Non analitic terms nr4 = coef.get("nr4", []) @@ -1822,16 +1822,16 @@ def _phir(self, tau, delta): for n, d, t, a, e, b, g in zip(nr3, d3, t3, a3, e3, b3, g3): fir += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2) fird += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - d/delta-2*a*(delta-e)) + d/delta-2*a*(delta-e)) firdd += n*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - -2*a*delta**d + 4*a**2*delta**d*(delta-e)**2 - - 4*d*a*delta**(d-1)*(delta-e) + d*(d-1)*delta**(d-2)) + -2*a*delta**d + 4*a**2*delta**d*(delta-e)**2 - + 4*d*a*delta**(d-1)*(delta-e) + d*(d-1)*delta**(d-2)) firt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - t/tau-2*b*(tau-g)) + t/tau-2*b*(tau-g)) firtt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - (t/tau-2*b*(tau-g))**2-t/tau**2-2*b) + (t/tau-2*b*(tau-g))**2-t/tau**2-2*b) firdt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - t/tau-2*b*(tau-g))*(d/delta-2*a*(delta-e)) + t/tau-2*b*(tau-g))*(d/delta-2*a*(delta-e)) # Non analitic terms nr4 = self._constants.get("nr4", []) @@ -1936,11 +1936,11 @@ def _virial(self, T): g3 = self._constants.get("gamma3", []) for n, d, t, a, e, b, g in zip(nr3, d3, t3, a3, e3, b3, g3): B += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - d/delta-2*a*(delta-e)) + d/delta-2*a*(delta-e)) C += n*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - -2*a*delta**d+4*a**2*delta**d*( - delta-e)**2-4*d*a*delta**2*( - delta-e)+d*2*delta) + -2*a*delta**d+4*a**2*delta**d*( + delta-e)**2-4*d*a*delta**2*( + delta-e)+d*2*delta) # Non analitic terms nr4 = self._constants.get("nr4", []) From 724d7e4b35c014ac858ccf3f4ac92ba8e45beee3 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 16:37:22 -0500 Subject: [PATCH 007/102] Correct flake8 W391 complaint. W391 blank line at end of file --- docs/conf.py | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index fae2f1e..b82c152 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -312,4 +312,3 @@ # Autosummary configuration autosummary_generate = True - From 00017db1e2b63709d6dd2a063d65f00d6e0b118d Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 16:40:54 -0500 Subject: [PATCH 008/102] Correct flake8 C812 complaints. C812 missing trailing comma --- docs/conf.py | 4 ++-- iapws/humidAir.py | 2 +- setup.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index b82c152..b16fceb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -46,7 +46,7 @@ 'sphinx.ext.viewcode', 'sphinx.ext.autosummary', 'sphinx.ext.napoleon', - 'numpydoc' + 'numpydoc', ] # Add any paths that contain templates here, relative to this directory. @@ -271,7 +271,7 @@ # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'iapws', u'iapws Documentation', - [author], 1) + [author], 1), ] # If true, show URL addresses after external links. diff --git a/iapws/humidAir.py b/iapws/humidAir.py index 70ff7c1..ca0bc97 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -286,7 +286,7 @@ class Air(MEoSBlend): "titao": [25.36365, 16.90741], "ao_exp2": [-0.197938904], "titao2": [87.31279], - "sum2": [2./3] + "sum2": [2./3], } _constants = { diff --git a/setup.py b/setup.py index 25c6cdd..fcd9061 100644 --- a/setup.py +++ b/setup.py @@ -36,6 +36,6 @@ "Topic :: Scientific/Engineering", "Topic :: Scientific/Engineering :: Chemistry", "Topic :: Scientific/Engineering :: Physics", - "Topic :: Software Development :: Libraries :: Python Modules" - ] + "Topic :: Software Development :: Libraries :: Python Modules", + ], ) From 69e3fbb33719b3b50d5f28d0810dbea391101419 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 16:42:21 -0500 Subject: [PATCH 009/102] Correct flake8 C101 complaint. C101 Coding magic comment not found --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index fcd9061..a57894c 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,5 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- from setuptools import setup import io # for backwards compatibility with Python 2 From 5bd4a691b6d9064de1f3fbb921b9943efe565d8b Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 16:53:02 -0500 Subject: [PATCH 010/102] Correct flake8 C407 complaints. C407 Unnecessary list comprehension - 'sum' can take a generator. See: https://github.com/adamchainz/flake8-comprehensions --- iapws/_iapws.py | 62 +++++++++++++++++++++++------------------------ iapws/ammonia.py | 10 ++++---- iapws/humidAir.py | 24 +++++++++--------- 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/iapws/_iapws.py b/iapws/_iapws.py index 7c6acd4..19c4b44 100644 --- a/iapws/_iapws.py +++ b/iapws/_iapws.py @@ -290,38 +290,38 @@ def _Liquid(T, P=0.1): n = [None, 4, 5, 7, None, None, 4, 5, 7, 8, 9, 1, 3, 5, 6, 7] m = [None, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 1, 3, 4, 5, 6, 7, 9] - suma1 = sum([a[i]*alfa**n[i] for i in range(1, 4)]) - suma2 = sum([b[i]*beta**m[i] for i in range(1, 5)]) + suma1 = sum(a[i]*alfa**n[i] for i in range(1, 4)) + suma2 = sum(b[i]*beta**m[i] for i in range(1, 5)) go = R*Tr*(c[1]+c[2]*tau+c[3]*tau*log(tau)+suma1+suma2) - suma1 = sum([a[i]*alfa**n[i] for i in range(6, 11)]) - suma2 = sum([b[i]*beta**m[i] for i in range(5, 11)]) + suma1 = sum(a[i]*alfa**n[i] for i in range(6, 11)) + suma2 = sum(b[i]*beta**m[i] for i in range(5, 11)) vo = R*Tr/Po/1000*(a[5]+suma1+suma2) - suma1 = sum([a[i]*alfa**n[i] for i in range(11, 16)]) - suma2 = sum([b[i]*beta**m[i] for i in range(11, 18)]) + suma1 = sum(a[i]*alfa**n[i] for i in range(11, 16)) + suma2 = sum(b[i]*beta**m[i] for i in range(11, 18)) vpo = R*Tr/Po**2/1000*(suma1+suma2) - suma1 = sum([n[i]*a[i]*alfa**(n[i]+1) for i in range(1, 4)]) - suma2 = sum([m[i]*b[i]*beta**(m[i]+1) for i in range(1, 5)]) + suma1 = sum(n[i]*a[i]*alfa**(n[i]+1) for i in range(1, 4)) + suma2 = sum(m[i]*b[i]*beta**(m[i]+1) for i in range(1, 5)) so = -R*(c[2]+c[3]*(1+log(tau))+suma1-suma2) - suma1 = sum([n[i]*(n[i]+1)*a[i]*alfa**(n[i]+2) for i in range(1, 4)]) - suma2 = sum([m[i]*(m[i]+1)*b[i]*beta**(m[i]+2) for i in range(1, 5)]) + suma1 = sum(n[i]*(n[i]+1)*a[i]*alfa**(n[i]+2) for i in range(1, 4)) + suma2 = sum(m[i]*(m[i]+1)*b[i]*beta**(m[i]+2) for i in range(1, 5)) cpo = -R*(c[3]+tau*suma1+tau*suma2) - suma1 = sum([n[i]*a[i]*alfa**(n[i]+1) for i in range(6, 11)]) - suma2 = sum([m[i]*b[i]*beta**(m[i]+1) for i in range(5, 11)]) + suma1 = sum(n[i]*a[i]*alfa**(n[i]+1) for i in range(6, 11)) + suma2 = sum(m[i]*b[i]*beta**(m[i]+1) for i in range(5, 11)) vto = R/Po/1000*(suma1-suma2) # This properties are only neccessary for computing thermodynamic # properties at pressures different from 0.1 MPa - suma1 = sum([n[i]*(n[i]+1)*a[i]*alfa**(n[i]+2) for i in range(6, 11)]) - suma2 = sum([m[i]*(m[i]+1)*b[i]*beta**(m[i]+2) for i in range(5, 11)]) + suma1 = sum(n[i]*(n[i]+1)*a[i]*alfa**(n[i]+2) for i in range(6, 11)) + suma2 = sum(m[i]*(m[i]+1)*b[i]*beta**(m[i]+2) for i in range(5, 11)) vtto = R/Tr/Po/1000*(suma1+suma2) - suma1 = sum([n[i]*a[i]*alfa**(n[i]+1) for i in range(11, 16)]) - suma2 = sum([m[i]*b[i]*beta**(m[i]+1) for i in range(11, 18)]) + suma1 = sum(n[i]*a[i]*alfa**(n[i]+1) for i in range(11, 16)) + suma2 = sum(m[i]*b[i]*beta**(m[i]+1) for i in range(11, 18)) vpto = R/Po**2/1000*(suma1-suma2) if P != 0.1: @@ -367,19 +367,19 @@ def _Liquid(T, P=0.1): a = [None, 280.68, 511.45, 61.131, 0.45903] b = [None, -1.9, -7.7, -19.6, -40] T_ = T/300 - mu = sum([a[i]*T_**b[i] for i in range(1, 5)])/1e6 + mu = sum(a[i]*T_**b[i] for i in range(1, 5))/1e6 propiedades["mu"] = mu # Thermal conductivity correlation, Eq 8 c = [None, 1.6630, -1.7781, 1.1567, -0.432115] d = [None, -1.15, -3.4, -6.0, -7.6] - k = sum([c[i]*T_**d[i] for i in range(1, 5)]) + k = sum(c[i]*T_**d[i] for i in range(1, 5)) propiedades["k"] = k # Dielectric constant correlation, Eq 9 e = [None, -43.7527, 299.504, -399.364, 221.327] f = [None, -0.05, -1.47, -2.11, -2.31] - epsilon = sum([e[i]*T_**f[i] for i in range(1, 5)]) + epsilon = sum(e[i]*T_**f[i] for i in range(1, 5)) propiedades["epsilon"] = epsilon return propiedades @@ -735,7 +735,7 @@ def _Viscosity(rho, T, fase=None, drho=None): # Eq 11 H = [1.67752, 2.20462, 0.6366564, -0.241605] - mu0 = 100*Tr**0.5/sum([Hi/Tr**i for i, Hi in enumerate(H)]) + mu0 = 100*Tr**0.5/sum(Hi/Tr**i for i, Hi in enumerate(H)) # Eq 12 I = [0, 1, 2, 3, 0, 1, 2, 3, 5, 0, 1, 2, 3, 4, 0, 1, 0, 3, 4, 3, 5] @@ -744,7 +744,7 @@ def _Viscosity(rho, T, fase=None, drho=None): 0.188797e1, 0.126613e1, 0.120573, -0.281378, -0.906851, -0.772479, -0.489837, -0.257040, 0.161913, 0.257399, -0.325372e-1, 0.698452e-1, 0.872102e-2, -0.435673e-2, -0.593264e-3] - mu1 = exp(Dr*sum([(1/Tr-1)**i*h*(Dr-1)**j for i, j, h in zip(I, J, Hij)])) + mu1 = exp(Dr*sum((1/Tr-1)**i*h*(Dr-1)**j for i, j, h in zip(I, J, Hij))) # Critical enhancement if fase and drho: @@ -824,7 +824,7 @@ def _ThCond(rho, T, fase=None, drho=None): # Eq 16 no = [2.443221e-3, 1.323095e-2, 6.770357e-3, -3.454586e-3, 4.096266e-4] - k0 = Tr**0.5/sum([n/Tr**i for i, n in enumerate(no)]) + k0 = Tr**0.5/sum(n/Tr**i for i, n in enumerate(no)) # Eq 17 I = [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, @@ -837,7 +837,7 @@ def _ThCond(rho, T, fase=None, drho=None): -1.40944978, 0.275418278, -0.0205938816, -1.21051378, 1.60812989, -0.621178141, 0.0716373224, -2.7203370, 4.57586331, -3.18369245, 1.1168348, -0.19268305, 0.012913842] - k1 = exp(d*sum([(1/Tr-1)**i*n*(d-1)**j for i, j, n in zip(I, J, nij)])) + k1 = exp(d*sum((1/Tr-1)**i*n*(d-1)**j for i, j, n in zip(I, J, nij))) # Critical enhancement if fase: @@ -861,7 +861,7 @@ def _ThCond(rho, T, fase=None, drho=None): else: ai = [1.11999926419994, 0.595748562571649, 9.88952565078920, -10.3255051147040, 4.66861294457414, -0.503243546373828] - drho = 1/sum([a*d**i for i, a in enumerate(ai)])*rhoc/Pc + drho = 1/sum(a*d**i for i, a in enumerate(ai))*rhoc/Pc DeltaX = d*(Pc/rhoc*fase.drhodP_T-Pc/rhoc*drho*1.5/Tr) if DeltaX < 0: @@ -1142,8 +1142,8 @@ def _Conductivity(rho, T): B = [16., 11.6, 3.26e-4, -2.3e-6, 1.1e-8] t = T-273.15 - Loo = A[0]-1/(1/A[1]+sum([A[i+2]*t**(i+1) for i in range(4)])) # Eq 5 - rho_h = B[0]-1/(1/B[1]+sum([B[i+2]*t**(i+1) for i in range(3)])) # Eq 6 + Loo = A[0]-1/(1/A[1]+sum(A[i+2]*t**(i+1) for i in range(4))) # Eq 5 + rho_h = B[0]-1/(1/B[1]+sum(B[i+2]*t**(i+1) for i in range(3))) # Eq 6 # Eq 4 L_o = (rho_h-rho_)*Loo/rho_h @@ -1185,7 +1185,7 @@ def _D2O_Viscosity(rho, T): rhor = rho/358.0 no = [1.0, 0.940695, 0.578377, -0.202044] - fi0 = Tr**0.5/sum([n/Tr**i for i, n in enumerate(no)]) + fi0 = Tr**0.5/sum(n/Tr**i for i, n in enumerate(no)) Li = [0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 0, 1, 2, 5, 0, 1, 2, 3, 0, 1, 3, 5, 0, 1, 5, 3] @@ -1235,11 +1235,11 @@ def _D2O_ThCond(rho, T): tau = Tr/(abs(Tr-1.1)+1.1) no = [1.0, 37.3223, 22.5485, 13.0465, 0.0, -2.60735] - Lo = sum([Li*Tr**i for i, Li in enumerate(no)]) + Lo = sum(Li*Tr**i for i, Li in enumerate(no)) nr = [483.656, -191.039, 73.0358, -7.57467] Lr = -167.31*(1-exp(-2.506*rhor))+sum( - [Li*rhor**(i+1) for i, Li in enumerate(nr)]) + Li*rhor**(i+1) for i, Li in enumerate(nr)) f1 = exp(0.144847*Tr-5.64493*Tr**2) f2 = exp(-2.8*(rhor-1)**2)-0.080738543*exp(-17.943*(rhor-0.125698)**2) @@ -1484,7 +1484,7 @@ def _Henry(T, gas, liquid="H2O"): else: ai = [-7.896657, 24.73308, -27.81128, 9.355913, -9.220083] bi = [1, 1.89, 2, 3, 3.6] - ps = Pc*exp(1/Tr*sum([a*tau**b for a, b in zip(ai, bi)])) + ps = Pc*exp(1/Tr*sum(a*tau**b for a, b in zip(ai, bi))) # Select values from Table 2 par = { @@ -1609,7 +1609,7 @@ def _Kvalue(T, gas, liquid="H2O"): ci = [2.7072, 0.58662, -1.3069, -45.663] di = [0.374, 1.45, 2.6, 12.3] q = -0.024552 - f = sum([c*tau**d for c, d in zip(ci, di)]) + f = sum(c*tau**d for c, d in zip(ci, di)) # Select values from Table 2 par = {"He": (2267.4082, -2.9616, -3.2604, 7.8819), diff --git a/iapws/ammonia.py b/iapws/ammonia.py index b569cfc..284717e 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -114,7 +114,7 @@ def _visco(self, rho, T, fase=None): # Eq 4 a = [4.99318220, -0.61122364, 0.0, 0.18535124, -0.11160946] - omega = exp(sum([ai*log(T_)**i for i, ai in enumerate(a)])) + omega = exp(sum(ai*log(T_)**i for i, ai in enumerate(a))) # Eq 2, Zero-Density Limit muo = 2.1357*(T*self.M)**0.5/sigma**2/omega @@ -124,7 +124,7 @@ def _visco(self, rho, T, fase=None): -0.13019164e5, 0.33414230e5, -0.58711743e5, 0.71426686e5, -0.59834012e5, 0.33652741e5, -0.1202735e5, 0.24348205e4, -0.20807957e3] - Bn = 0.6022137*sigma**3*sum([c*T_**(-i/2) for i, c in enumerate(cv)]) + Bn = 0.6022137*sigma**3*sum(c*T_**(-i/2) for i, c in enumerate(cv)) # Eq 7 mub = Bn*muo*rho @@ -133,7 +133,7 @@ def _visco(self, rho, T, fase=None): 1.67668649e-4, -1.49710093e-4, 0.77012274e-4] ji = [2, 4, 0, 1, 2, 3, 4] ii = [2, 2, 3, 3, 4, 4, 4] - mur = sum([d/T_**j*rho**i for d, j, i in zip(dij, ji, ii)]) + mur = sum(d/T_**j*rho**i for d, j, i in zip(dij, ji, ii)) # Eq 1 mu = muo + mub + mur @@ -172,11 +172,11 @@ def _thermo(self, rho, T, fase): # Eq 6 no = [0.3589e-1, -0.1750e-3, 0.4551e-6, 0.1685e-9, -0.4828e-12] - Lo = sum([n*T**i for i, n in enumerate(no)]) + Lo = sum(n*T**i for i, n in enumerate(no)) # Eq 7 nb = [0.16207e-3, 0.12038e-5, -0.23139e-8, 0.32749e-11] - L_ = sum([n*rho**(i+1) for i, n in enumerate(nb)]) + L_ = sum(n*rho**(i+1) for i, n in enumerate(nb)) # Critical enchancement t = abs(T-405.4)/405.4 diff --git a/iapws/humidAir.py b/iapws/humidAir.py index ca0bc97..0a7558f 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -115,28 +115,28 @@ def _virial(T): ci = [66.5687, -238.834, -176.755] di = [-0.237, -1.048, -3.183] - Baw = 1e-6*sum([c*T_**d for c, d in zip(ci, di)]) # Eq 7 - Caaw = 1e-6*sum([a/T_**i for i, a in enumerate(ai)]) # Eq 8 - Caww = -1e-6*exp(sum([b/T_**i for i, b in enumerate(bi)])) # Eq 9 + Baw = 1e-6*sum(c*T_**d for c, d in zip(ci, di)) # Eq 7 + Caaw = 1e-6*sum(a/T_**i for i, a in enumerate(ai)) # Eq 8 + Caww = -1e-6*exp(sum(b/T_**i for i, b in enumerate(bi))) # Eq 9 # Eq T56 - Bawt = 1e-6*T_/T*sum([c*d*T_**(d-1) for c, d in zip(ci, di)]) + Bawt = 1e-6*T_/T*sum(c*d*T_**(d-1) for c, d in zip(ci, di)) # Eq T57 Bawtt = 1e-6*T_**2/T**2*sum( - [c*d*(d-1)*T_**(d-2) for c, d in zip(ci, di)]) + c*d*(d-1)*T_**(d-2) for c, d in zip(ci, di)) # Eq T59 - Caawt = -1e-6*T_/T*sum([i*a*T_**(-i-1) for i, a in enumerate(ai)]) + Caawt = -1e-6*T_/T*sum(i*a*T_**(-i-1) for i, a in enumerate(ai)) # Eq T60 Caawtt = 1e-6*T_**2/T**2*sum( - [i*(i+1)*a*T_**(-i-2) for i, a in enumerate(ai)]) + i*(i+1)*a*T_**(-i-2) for i, a in enumerate(ai)) # Eq T62 - Cawwt = 1e-6*T_/T*sum([i*b*T_**(-i-1) for i, b in enumerate(bi)]) * \ - exp(sum([b/T_**i for i, b in enumerate(bi)])) + Cawwt = 1e-6*T_/T*sum(i*b*T_**(-i-1) for i, b in enumerate(bi)) * \ + exp(sum(b/T_**i for i, b in enumerate(bi))) # Eq T63 Cawwtt = -1e-6*T_**2/T**2*(( - sum([i*(i+1)*b*T_**(-i-2) for i, b in enumerate(bi)]) + - sum([i*b*T_**(-i-1) for i, b in enumerate(bi)])**2) * - exp(sum([b/T_**i for i, b in enumerate(bi)]))) + sum(i*(i+1)*b*T_**(-i-2) for i, b in enumerate(bi)) + + sum(i*b*T_**(-i-1) for i, b in enumerate(bi))**2) * + exp(sum(b/T_**i for i, b in enumerate(bi)))) # Virial coefficient for air, using too the general virial procedure air = Air() From ce17aa0d32ea4c4721d94b8b1e77f810b132b33c Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 16:57:21 -0500 Subject: [PATCH 011/102] Fix flake8 N813 complaint. N813 camelcase 'Boltzmann' imported as lowercase 'kb' --- iapws/ammonia.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iapws/ammonia.py b/iapws/ammonia.py index 284717e..964f2d8 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -14,7 +14,7 @@ from math import exp, log, pi import warnings -from scipy.constants import Boltzmann as kb +from scipy.constants import Boltzmann from .iapws95 import MEoS, IAPWS95, mainClassDoc @@ -183,7 +183,7 @@ def _thermo(self, rho, T, fase): dPT = 1e5*(2.18-0.12/exp(17.8*t)) nb = 1e-5*(2.6+1.6*t) - DL = 1.2*kb*T**2/6/pi/nb/(1.34e-10/t**0.63*(1+t**0.5))*dPT**2 * \ + DL = 1.2*Boltzmann*T**2/6/pi/nb/(1.34e-10/t**0.63*(1+t**0.5))*dPT**2 * \ 0.423e-8/t**1.24*(1+t**0.5/0.7) # Add correction for entire range of temperature, Eq 10 From d0e8efe36c3b26abe777c753b735b72f93d865d4 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 17:02:21 -0500 Subject: [PATCH 012/102] Correct flake8 N811 complaint. N811 constant 'M' imported as non constant 'Mw' Also avoid some ambiguity with local 'Mw' at line 926, but it would still be nice for there to be more clarity. --- iapws/humidAir.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iapws/humidAir.py b/iapws/humidAir.py index 0a7558f..f1a59e8 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -19,7 +19,7 @@ from scipy.optimize import fsolve -from ._iapws import M as Mw +from ._iapws import M as MW from ._iapws import _Ice from ._utils import deriv_G from .iapws95 import MEoS, IAPWS95, mainClassDoc @@ -633,7 +633,7 @@ def calculo(self): A = self.kwargs["A"] elif self._composition == "xa": xa = self.kwargs["xa"] - A = xa/(1-(1-xa)*(1-Mw/Ma)) + A = xa/(1-(1-xa)*(1-MW/Ma)) # Thermodynamic definition if self._mode == "TP": @@ -681,7 +681,7 @@ def f(T): # Saturation related properties A_sat = self._eq(self.T, self.P) - self.xa_sat = A_sat*Mw/Ma/(1-A_sat*(1-Mw/Ma)) + self.xa_sat = A_sat*MW/Ma/(1-A_sat*(1-MW/Ma)) self.RH = (1-self.xa)/(1-self.xa_sat) def derivative(self, z, x, y): @@ -809,9 +809,9 @@ def _coligative(self, rho, A, fav): prop = {} prop["mu"] = fav["fira"] prop["muw"] = fav["fir"]+rho*fav["fird"]-A*fav["fira"] - prop["M"] = 1/((1-A)/Mw+A/Ma) + prop["M"] = 1/((1-A)/MW+A/Ma) prop["HR"] = 1/A-1 - prop["xa"] = A*Mw/Ma/(1-A*(1-Mw/Ma)) + prop["xa"] = A*MW/Ma/(1-A*(1-MW/Ma)) prop["xw"] = 1-prop["xa"] return prop From 60265e577efd61825cd1201e7fe880bdf53d177a Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 17:16:30 -0500 Subject: [PATCH 013/102] Correct flake8 W504 complaints. W504 line break after binary operator --- iapws/_iapws.py | 12 ++++++------ iapws/ammonia.py | 20 ++++++++++---------- iapws/humidAir.py | 18 +++++++++--------- iapws/iapws08.py | 14 +++++++------- iapws/iapws95.py | 44 ++++++++++++++++++++++---------------------- iapws/iapws97.py | 12 ++++++------ 6 files changed, 60 insertions(+), 60 deletions(-) diff --git a/iapws/_iapws.py b/iapws/_iapws.py index 19c4b44..2be0c0e 100644 --- a/iapws/_iapws.py +++ b/iapws/_iapws.py @@ -557,8 +557,8 @@ def _Supercooled(T, P): prop["g"] = phir+(tau+1)*(x*L+x*log(x)+(1-x)*log(1-x)+omega*x*(1-x)) # Eq 14 - prop["s"] = -R*((tau+1)/2*Lt*(fi+1) + - (x*L+x*log(x)+(1-x)*log(1-x)+omega*x*(1-x))+phirt) + prop["s"] = -R*((tau+1)/2*Lt*(fi+1) + + (x*L+x*log(x)+(1-x)*log(1-x)+omega*x*(1-x))+phirt) # Basic derived state properties prop["h"] = prop["g"]+T*prop["s"] @@ -569,8 +569,8 @@ def _Supercooled(T, P): prop["xkappa"] = prop["rho"]/rho0**2/R*1000/Tll*( (tau+1)/2*(Xi*(Lp-omega0*fi)**2-(fi+1)*Lpp)-phirpp) prop["alfap"] = prop["rho"]/rho0/Tll*( - Ltp/2*(tau+1)*(fi+1) + (omega0*(1-fi**2)/2+Lp*(fi+1))/2 - - (tau+1)*Lt/2*Xi*(Lp-omega0*fi) + phirtp) + Ltp/2*(tau+1)*(fi+1) + (omega0*(1-fi**2)/2+Lp*(fi+1))/2 + - (tau+1)*Lt/2*Xi*(Lp-omega0*fi) + phirtp) prop["cp"] = -R*(tau+1)*(Lt*(fi+1)+(tau+1)/2*(Ltt*(fi+1)-Lt**2*Xi)+phirtt) # Eq 16 @@ -691,8 +691,8 @@ def _Melting_Pressure(T, ice="Ih"): Tref = 355 Pref = 2216.000 Tita = T/Tref - P = Pref*exp(1.73683*(1-1./Tita)-0.544606e-1*(1-Tita**5) + - 0.806106e-7*(1-Tita**22)) + P = Pref*exp(1.73683*(1-1./Tita)-0.544606e-1*(1-Tita**5) + + 0.806106e-7*(1-Tita**22)) else: raise NotImplementedError("Incoming out of bound") return P diff --git a/iapws/ammonia.py b/iapws/ammonia.py index 964f2d8..968b4aa 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -277,10 +277,10 @@ def _prop(self, rho, T, x): prop["a"] = prop["u"]-T*prop["s"] cvR = -tau0**2*fiott - tau**2*firtt prop["cv"] = R*cvR - prop["cp"] = R*(cvR+(1+delta*fird-delta*tau*firdt)**2 / - (1+2*delta*fird+delta**2*firdd)) - prop["w"] = (R*T*1000*(1+2*delta*fird+delta**2*firdd + - (1+delta*fird-delta*tau*firdt)**2 / cvR))**0.5 + prop["cp"] = R*(cvR+(1+delta*fird-delta*tau*firdt)**2 + / (1+2*delta*fird+delta**2*firdd)) + prop["w"] = (R*T*1000*(1+2*delta*fird+delta**2*firdd + + (1+delta*fird-delta*tau*firdt)**2 / cvR))**0.5 prop["fugH2O"] = Z*exp(fir+delta*fird-x*F) prop["fugNH3"] = Z*exp(fir+delta*fird+(1-x)*F) return prop @@ -424,12 +424,12 @@ def _phir(self, rho, T, x): # Density reducing value, Eq 5 b = 0.8978069 rhoc12 = 1/(1.2395117/2*(1/IAPWS95.rhoc+1/NH3.rhoc)) - rhon = 1/((1-x)**2/IAPWS95.rhoc + x**2/NH3.rhoc + - 2*x*(1-x**b)/rhoc12) - drhonx = -(2*b*x**b/rhoc12 + 2*(1-x**b)/rhoc12 + - 2*x/NH3.rhoc - 2*(1-x)/IAPWS95.rhoc)/( - 2*x*(1-x**b)/rhoc12 + x**2/NH3.rhoc + - (1-x)**2/IAPWS95.rhoc)**2 + rhon = 1/((1-x)**2/IAPWS95.rhoc + x**2/NH3.rhoc + + 2*x*(1-x**b)/rhoc12) + drhonx = -(2*b*x**b/rhoc12 + 2*(1-x**b)/rhoc12 + + 2*x/NH3.rhoc - 2*(1-x)/IAPWS95.rhoc)/( + 2*x*(1-x**b)/rhoc12 + x**2/NH3.rhoc + + (1-x)**2/IAPWS95.rhoc)**2 tau = Tn/T delta = rho/rhon diff --git a/iapws/humidAir.py b/iapws/humidAir.py index f1a59e8..a5a9746 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -134,9 +134,9 @@ def _virial(T): exp(sum(b/T_**i for i, b in enumerate(bi))) # Eq T63 Cawwtt = -1e-6*T_**2/T**2*(( - sum(i*(i+1)*b*T_**(-i-2) for i, b in enumerate(bi)) + - sum(i*b*T_**(-i-1) for i, b in enumerate(bi))**2) * - exp(sum(b/T_**i for i, b in enumerate(bi)))) + sum(i*(i+1)*b*T_**(-i-2) for i, b in enumerate(bi)) + + sum(i*b*T_**(-i-1) for i, b in enumerate(bi))**2) + * exp(sum(b/T_**i for i, b in enumerate(bi)))) # Virial coefficient for air, using too the general virial procedure air = Air() @@ -491,8 +491,8 @@ def _thermo(self, rho, T, fase=None): Xq = Xi/qd # Eq 8 - Omega = 2/pi*((fase.cp-fase.cv)/fase.cp*atan(Xq) + - fase.cv/fase.cp*(Xq)) + Omega = 2/pi*((fase.cp-fase.cv)/fase.cp*atan(Xq) + + fase.cv/fase.cp*(Xq)) # Eq 9 Omega0 = 2/pi*(1-exp(-1/(1/Xq+Xq**2/3*rhoc**2/rho**2))) @@ -771,8 +771,8 @@ def _prop(self, T, rho, fav): prop["xkappa"] = 1e3/(rho**2*(2*fav["fird"]+rho*fav["firdd"])) # Eq T8 prop["ks"] = 1000*fav["firtt"]/rho**2/( # Eq T9 fav["firtt"]*(2*fav["fird"]+rho*fav["firdd"])-rho*fav["firdt"]**2) - prop["w"] = (rho**2*1000*(fav["firtt"]*fav["firdd"]-fav["firdt"]**2) / - fav["firtt"]+2*rho*fav["fird"]*1000)**0.5 # Eq T10 + prop["w"] = (rho**2*1000*(fav["firtt"]*fav["firdd"]-fav["firdt"]**2) + / fav["firtt"]+2*rho*fav["fird"]*1000)**0.5 # Eq T10 return prop def _coligative(self, rho, A, fav): @@ -871,8 +871,8 @@ def _fav(self, T, rho, A): # Eq T14 prop["fird"] = (1-A)**2*fv["fird"]+A**2*fa["fird"]+fmix["fird"] # Eq T15 - prop["firaa"] = rho*(2*fv["fird"]+rhov*fv["firdd"] + - 2*fa["fird"]+rhoa*fa["firdd"])+fmix["firaa"] + prop["firaa"] = rho*(2*fv["fird"]+rhov*fv["firdd"] + + 2*fa["fird"]+rhoa*fa["firdd"])+fmix["firaa"] # Eq T16 prop["firat"] = -fv["firt"]-rhov*fv["firdt"]+fa["firt"] + \ rhoa*fa["firdt"]+fmix["firat"] diff --git a/iapws/iapws08.py b/iapws/iapws08.py index 7b7f650..c9da272 100644 --- a/iapws/iapws08.py +++ b/iapws/iapws08.py @@ -219,8 +219,8 @@ def calculo(self): self.xkappa = -prop["gpp"]/prop["gp"] self.ks = (prop["gtp"]**2-prop["gtt"]*prop["gpp"])/prop["gp"] / \ prop["gtt"] - self.w = prop["gp"]*(prop["gtt"]*1000/(prop["gtp"]**2 - - prop["gtt"]*1000*prop["gpp"]*1e-6))**0.5 + self.w = prop["gp"]*(prop["gtt"]*1000/( + prop["gtp"]**2 - prop["gtt"]*1000*prop["gpp"]*1e-6))**0.5 # Thermal conductivity calculation if "thcond" in pw: @@ -763,8 +763,8 @@ def _critNaCl(x): raise NotImplementedError("Incoming out of bound") T1 = Tc*(1 + 2.3e1*x - 3.3e2*x**1.5 - 1.8e3*x**2) - T2 = Tc*(1 + 1.757e1*x - 3.026e2*x**1.5 + 2.838e3*x**2 - 1.349e4*x**2.5 + - 3.278e4*x**3 - 3.674e4*x**3.5 + 1.437e4*x**4) + T2 = Tc*(1 + 1.757e1*x - 3.026e2*x**1.5 + 2.838e3*x**2 - 1.349e4*x**2.5 + + 3.278e4*x**3 - 3.674e4*x**3.5 + 1.437e4*x**4) f1 = (abs(10000*x-10-1)-abs(10000*x-10+1))/4+0.5 f2 = (abs(10000*x-10+1)-abs(10000*x-10-1))/4+0.5 @@ -772,9 +772,9 @@ def _critNaCl(x): tc = f1*T1+f2*T2 # Eq 7 - rc = rhoc*(1 + 1.7607e2*x - 2.9693e3*x**1.5 + 2.4886e4*x**2 - - 1.1377e5*x**2.5 + 2.8847e5*x**3 - 3.8195e5*x**3.5 + - 2.0633e5*x**4) + rc = rhoc*(1 + 1.7607e2*x - 2.9693e3*x**1.5 + 2.4886e4*x**2 + - 1.1377e5*x**2.5 + 2.8847e5*x**3 - 3.8195e5*x**3.5 + + 2.0633e5*x**4) # Eq 8 DT = tc-Tc diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 5830198..a22b9ba 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -167,8 +167,8 @@ def _phird(tau, delta, coef): Fd = -2*C*F*(delta-1) Delta = Tita**2+B*((delta-1)**2)**a - Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**(0.5/bt-1) + - 2*B*a*((delta-1)**2)**(a-1)) + Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**(0.5/bt-1) + + 2*B*a*((delta-1)**2)**(a-1)) DeltaBd = b*Delta**(b-1)*Deltad fird += n*(Delta**b*(F+delta*Fd)+DeltaBd*delta*F) @@ -1486,8 +1486,8 @@ def fill(self, fase, estado): fase.g = fase.h-self.T*fase.s fase.Z = self.P*fase.v/self.T/self.R*1e3 - fase.fi = exp(estado["fir"]+estado["delta"]*estado["fird"] - - log(1+estado["delta"]*estado["fird"])) + fase.fi = exp(estado["fir"]+estado["delta"]*estado["fird"] + - log(1+estado["delta"]*estado["fird"])) fase.f = fase.fi*self.P fase.cv = estado["cv"] @@ -1824,8 +1824,8 @@ def _phir(self, tau, delta): fird += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( d/delta-2*a*(delta-e)) firdd += n*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - -2*a*delta**d + 4*a**2*delta**d*(delta-e)**2 - - 4*d*a*delta**(d-1)*(delta-e) + d*(d-1)*delta**(d-2)) + -2*a*delta**d + 4*a**2*delta**d*(delta-e)**2 + - 4*d*a*delta**(d-1)*(delta-e) + d*(d-1)*delta**(d-2)) firt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( t/tau-2*b*(tau-g)) firtt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( @@ -1852,15 +1852,15 @@ def _phir(self, tau, delta): Fdt = 4*C*D*F*(delta-1)*(tau-1) Delta = Tita**2+B*((delta-1)**2)**a - Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**(0.5/bt-1) + - 2*B*a*((delta-1)**2)**(a-1)) + Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**(0.5/bt-1) + + 2*B*a*((delta-1)**2)**(a-1)) if delta == 1: Deltadd = 0 else: Deltadd = Deltad/(delta-1)+(delta-1)**2*( - 4*B*a*(a-1)*((delta-1)**2)**(a-2) + - 2*A**2/bt**2*(((delta-1)**2)**(0.5/bt-1))**2 + - A*Tita*4/bt*(0.5/bt-1)*((delta-1)**2)**(0.5/bt-2)) + 4*B*a*(a-1)*((delta-1)**2)**(a-2) + + 2*A**2/bt**2*(((delta-1)**2)**(0.5/bt-1))**2 + + A*Tita*4/bt*(0.5/bt-1)*((delta-1)**2)**(0.5/bt-2)) DeltaBd = b*Delta**(b-1)*Deltad DeltaBdd = b*(Delta**(b-1)*Deltadd+(b-1)*Delta**(b-2)*Deltad**2) @@ -1871,12 +1871,12 @@ def _phir(self, tau, delta): fir += n*Delta**b*delta*F fird += n*(Delta**b*(F+delta*Fd)+DeltaBd*delta*F) - firdd += n*(Delta**b*(2*Fd+delta*Fdd) + 2*DeltaBd*(F+delta*Fd) + - DeltaBdd*delta*F) + firdd += n*(Delta**b*(2*Fd+delta*Fdd) + 2*DeltaBd*(F+delta*Fd) + + DeltaBdd*delta*F) firt += n*delta*(DeltaBt*F+Delta**b*Ft) firtt += n*delta*(DeltaBtt*F+2*DeltaBt*Ft+Delta**b*Ftt) - firdt += n*(Delta**b*(Ft+delta*Fdt)+delta*DeltaBd*Ft + - DeltaBt*(F+delta*Fd)+DeltaBdt*delta*F) + firdt += n*(Delta**b*(Ft+delta*Fdt)+delta*DeltaBd*Ft + + DeltaBt*(F+delta*Fd)+DeltaBdt*delta*F) prop = {} prop["fir"] = fir @@ -1957,9 +1957,9 @@ def _virial(self, T): Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**( 0.5/bt-1)+2*B_*a*((delta-1)**2)**(a-1)) Deltadd = Deltad/(delta-1) + (delta-1)**2*( - 4*B_*a*(a-1)*((delta-1)**2)**(a-2) + - 2*A**2/bt**2*(((delta-1)**2)**(0.5/bt-1))**2 + - A*Tita*4/bt*(0.5/bt-1)*((delta-1)**2)**(0.5/bt-2)) + 4*B_*a*(a-1)*((delta-1)**2)**(a-2) + + 2*A**2/bt**2*(((delta-1)**2)**(0.5/bt-1))**2 + + A*Tita*4/bt*(0.5/bt-1)*((delta-1)**2)**(0.5/bt-2)) DeltaBd = b*Delta**(b-1)*Deltad DeltaBdd = b*(Delta**(b-1)*Deltadd+(b-1)*Delta**(b-2)*Deltad**2) F = exp(-C_*(delta-1)**2-D*(tau-1)**2) @@ -1967,8 +1967,8 @@ def _virial(self, T): Fdd = 2*C_*F*(2*C_*(delta-1)**2-1) B += n*(Delta**b*(F+delta*Fd)+DeltaBd*delta*F) - C += n*(Delta**b*(2*Fd+delta*Fdd)+2*DeltaBd*(F+delta*Fd) + - DeltaBdd*delta*F) + C += n*(Delta**b*(2*Fd+delta*Fdd)+2*DeltaBd*(F+delta*Fd) + + DeltaBdd*delta*F) prop = {} prop["B"] = B @@ -2429,8 +2429,8 @@ def _phiex(self, T): tau = self.Tc/T E = 0.278296458178592 ep = self.Tc/130 - fex = E*(-1/2/tau-3/ep**2*(tau+ep)*log(tau/ep)-9/2/ep+9*tau/2/ep**2 + - tau**2/2/ep**3) + fex = E*(-1/2/tau-3/ep**2*(tau+ep)*log(tau/ep)-9/2/ep+9*tau/2/ep**2 + + tau**2/2/ep**3) fext = E*(1/2/tau**2-3/tau/ep-3/ep**2*log(tau/ep)+3/2/ep**2+tau/ep**3) fextt = E*(-1/tau+1/ep)**3 return fex, fext, fextt diff --git a/iapws/iapws97.py b/iapws/iapws97.py index b0a9316..24d287c 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -1042,8 +1042,8 @@ def _Region2(T, P): propiedades["h"] = Tr*(got+grt)*R*T propiedades["s"] = R*(Tr*(got+grt)-(go+gr)) propiedades["cp"] = -R*Tr**2*(gott+grtt) - propiedades["cv"] = R*(-Tr**2*(gott+grtt)-(1+Pr*grp-Tr*Pr*grpt)**2 / - (1-Pr**2*grpp)) + propiedades["cv"] = R*(-Tr**2*(gott+grtt)-(1+Pr*grp-Tr*Pr*grpt)**2 + / (1-Pr**2*grpp)) propiedades["w"] = (R*T*1000*(1+2*Pr*grp+Pr**2*grp**2)/(1-Pr**2*grpp+( 1+Pr*grp-Tr*Pr*grpt)**2/Tr**2/(gott+grtt)))**0.5 propiedades["alfav"] = (1+Pr*grp-Tr*Pr*grpt)/(1+Pr*grp)/T @@ -1856,8 +1856,8 @@ def _Region3(rho, T): propiedades["s"] = R*(Tr*gt-g) propiedades["cp"] = R*(-Tr**2*gtt+(d*gd-d*Tr*gdt)**2/(2*d*gd+d**2*gdd)) propiedades["cv"] = -R*Tr**2*gtt - propiedades["w"] = sqrt(R*T*1000*(2*d*gd+d**2*gdd-(d*gd-d*Tr*gdt)**2 / - Tr**2/gtt)) + propiedades["w"] = sqrt(R*T*1000*(2*d*gd+d**2*gdd-(d*gd-d*Tr*gdt)**2 + / Tr**2/gtt)) propiedades["alfav"] = (gd-Tr*gdt)/(2*gd+d*gdd)/T propiedades["kt"] = 1/(2*d*gd+d**2*gdd)/rho/R/T*1000 propiedades["region"] = 3 @@ -3755,8 +3755,8 @@ def _Region5(T, P): propiedades["h"] = Tr*(got+grt)*R*T propiedades["s"] = R*(Tr*(got+grt)-(go+gr)) propiedades["cp"] = -R*Tr**2*(gott+grtt) - propiedades["cv"] = R*(-Tr**2*(gott+grtt)+((gop+grp)-Tr*(gopt+grpt))**2 / - (gopp+grpp)) + propiedades["cv"] = R*(-Tr**2*(gott+grtt)+((gop+grp)-Tr*(gopt+grpt))**2 + / (gopp+grpp)) propiedades["w"] = (R*T*1000*(1+2*Pr*grp+Pr**2*grp**2)/(1-Pr**2*grpp+( 1+Pr*grp-Tr*Pr*grpt)**2/Tr**2/(gott+grtt)))**0.5 propiedades["alfav"] = (1+Pr*grp-Tr*Pr*grpt)/(1+Pr*grp)/T From 1dd7d29bcdc7daae34e166c3585f76cba5f07d45 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 17:20:37 -0500 Subject: [PATCH 014/102] Correct flake8 D101 complaints. D100 Missing docstring in public module --- docs/conf.py | 2 ++ plots.py | 2 +- setup.py | 2 ++ test.py | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index b16fceb..95ad648 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,4 +1,6 @@ +#!/usr/bin/python # -*- coding: utf-8 -*- +"""Sphinx documentation config file.""" # # pychemqt documentation build configuration file, created by # sphinx-quickstart on Wed Jan 13 22:26:06 2016. diff --git a/plots.py b/plots.py index 8b7ff3d..daf3692 100644 --- a/plots.py +++ b/plots.py @@ -1,6 +1,6 @@ #!/usr/bin/python3 # -*- coding: utf-8 -*- - +"""Generate various plots using IAPWS.""" from math import pi, atan, log import matplotlib.pyplot as plt diff --git a/setup.py b/setup.py index a57894c..bc9af3d 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,7 @@ #!/usr/bin/python # -*- coding: utf-8 -*- +"""Install IAPWS module using setuptools.""" + from setuptools import setup import io # for backwards compatibility with Python 2 diff --git a/test.py b/test.py index 74b16ec..abd8e52 100644 --- a/test.py +++ b/test.py @@ -1,5 +1,6 @@ #!/usr/bin/python # -*- coding: utf-8 -*- +"""Test IAPWS mopdule.""" from math import log import sys From 2241328192f5b6184ec934f6b23c22bc40a84d04 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 17:25:05 -0500 Subject: [PATCH 015/102] Suppress flake8 F841 complaint. F841 local variable 'st' is assigned to but never used Since these tests are not currently working, I added a test that was almost certainly correct to suppress the flake8 complaint. Obviously, addressing the tests would be a better fix. ;-) --- test.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test.py b/test.py index abd8e52..0b0a3a7 100644 --- a/test.py +++ b/test.py @@ -2740,6 +2740,9 @@ def test_nh3h2o(self): # self.assertEqual(round(st["u"], 5), 0) # self.assertEqual(round(st["s"], 5), 0) + # Suppress flake8 error until tests are working. + self.assertIsInstance(st["u"], float) + nh3 = NH3(T=NH3.Tt, x=0) st = cl._prop(nh3.rho, NH3.Tt, 1) # self.assertEqual(round(st["u"], 5), 0) From 61ff112f91c6036b9d5bd9c1e3848023300b2437 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 17:29:09 -0500 Subject: [PATCH 016/102] Correct flake8 D202 complaints. D202 No blank lines allowed after function docstring --- iapws/_iapws.py | 1 - iapws/ammonia.py | 1 - iapws/iapws08.py | 2 -- iapws/iapws97.py | 1 - test.py | 1 - 5 files changed, 6 deletions(-) diff --git a/iapws/_iapws.py b/iapws/_iapws.py index 2be0c0e..3de7b37 100644 --- a/iapws/_iapws.py +++ b/iapws/_iapws.py @@ -459,7 +459,6 @@ def _Supercooled(T, P): IAPWS, Guideline on Thermodynamic Properties of Supercooled Water, http://iapws.org/relguide/Supercooled.html """ - # Check input in range of validity if P < 198.9: Tita = T/235.15 diff --git a/iapws/ammonia.py b/iapws/ammonia.py index 968b4aa..660e954 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -414,7 +414,6 @@ def _phir(self, rho, T, x): Properties of Ammonia-Water Mixtures, http://www.iapws.org/relguide/nh3h2o.pdf, Eq 3 """ - # Temperature reducing value, Eq 4 Tc12 = 0.9648407/2*(IAPWS95.Tc+NH3.Tc) Tn = (1-x)**2*IAPWS95.Tc + x**2*NH3.Tc + 2*x*(1-x**1.125455)*Tc12 diff --git a/iapws/iapws08.py b/iapws/iapws08.py index c9da272..4d91aa1 100644 --- a/iapws/iapws08.py +++ b/iapws/iapws08.py @@ -341,7 +341,6 @@ def _waterSupp(cls, T, P): @classmethod def _saline(cls, T, P, S): """Eq 4""" - # Check input in range of validity if T <= 261 or T > 353 or P <= 0 or P > 100 or S < 0 or S > 0.12: warnings.warn("Incoming out of bound") @@ -653,7 +652,6 @@ def _Tension_SeaWater(T, S): IAPWS, Guideline on the Surface Tension of Seawater, http://www.iapws.org/relguide/Seawater-Surf.html """ - # Check input parameters if 248.15 < T < 274.15: if S < 0 or S > 0.038: diff --git a/iapws/iapws97.py b/iapws/iapws97.py index 24d287c..9e4c62d 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -1815,7 +1815,6 @@ def _Region3(rho, T): >>> _Region3(500,750)["kt"] 0.00806710817 """ - I = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 8, 9, 9, 10, 10, 11] J = [0, 1, 2, 7, 10, 12, 23, 2, 6, 15, 17, 0, 2, 6, 7, 22, 26, 0, 2, 4, 16, diff --git a/test.py b/test.py index 0b0a3a7..38e7e2c 100644 --- a/test.py +++ b/test.py @@ -487,7 +487,6 @@ def test_auxiliarySaturation(self): def test_IAPWS97_1(self): """Table 5, pag 9""" - fluid = _Region1(300, 3) self.assertEqual(round(fluid["v"], 11), 0.00100215168) self.assertEqual(round(fluid["h"], 6), 115.331273) From da62a360427a58f780409a87d6f44567bbe4b377 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 17:32:51 -0500 Subject: [PATCH 017/102] Correct flake8 D209 complaints. D209 Multi-line docstring closing quotes should be on a separate line --- iapws/humidAir.py | 12 ++++++++---- iapws/iapws08.py | 12 ++++++++---- iapws/iapws95.py | 12 ++++++++---- iapws/iapws97.py | 6 ++++-- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/iapws/humidAir.py b/iapws/humidAir.py index a5a9746..74de3c2 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -222,8 +222,10 @@ def _fugacity(T, P, x): class MEoSBlend(MEoS): - """Special meos class to implement pseudocomponent blend and defining its - ancillary dew and bubble point""" + """ + Special meos class to implement pseudocomponent blend and defining its + ancillary dew and bubble point + """ @classmethod def _dewP(cls, T): """Using ancillary equation return the pressure of dew point""" @@ -685,8 +687,10 @@ def f(T): self.RH = (1-self.xa)/(1-self.xa_sat) def derivative(self, z, x, y): - """Wrapper derivative for custom derived properties - where x, y, z can be: P, T, v, rho, u, h, s, g, a""" + """ + Wrapper derivative for custom derived properties + where x, y, z can be: P, T, v, rho, u, h, s, g, a + """ return deriv_G(self, z, x, y, self) def _eq(self, T, P): diff --git a/iapws/iapws08.py b/iapws/iapws08.py index 4d91aa1..e417cb1 100644 --- a/iapws/iapws08.py +++ b/iapws/iapws08.py @@ -252,8 +252,10 @@ def calculo(self): self.haline = None def derivative(self, z, x, y): - """Wrapper derivative for custom derived properties - where x, y, z can be: P, T, v, u, h, s, g, a""" + """ + Wrapper derivative for custom derived properties + where x, y, z can be: P, T, v, u, h, s, g, a + """ return deriv_G(self, z, x, y, self) @classmethod @@ -289,8 +291,10 @@ def _waterIF97(cls, T, P): @classmethod def _waterSupp(cls, T, P): - """Get properties of pure water using the supplementary release SR7-09, - Table4 pag 6""" + """ + Get properties of pure water using the supplementary release SR7-09, + Table4 pag 6 + """ tau = (T-273.15)/40 pi = (P-0.101325)/100 diff --git a/iapws/iapws95.py b/iapws/iapws95.py index a22b9ba..e6b5f03 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -1553,8 +1553,10 @@ def fill(self, fase, estado): fase.n = None def derivative(self, z, x, y, fase): - """Wrapper derivative for custom derived properties - where x, y, z can be: P, T, v, rho, u, h, s, g, a""" + """ + Wrapper derivative for custom derived properties + where x, y, z can be: P, T, v, rho, u, h, s, g, a + """ return deriv_H(self, z, x, y, fase) def _saturation(self, T): @@ -2191,8 +2193,10 @@ def _dPdT_sat(cls, T): def mainClassDoc(): - """Function decorator used to automatic adiction of base class MEoS in - subclass __doc__""" + """ + Function decorator used to automatic adiction of base class MEoS in + subclass __doc__ + """ def decorator(f): # __doc__ is only writable in python3. # The doc build must be done with python3 so this snnippet do the work diff --git a/iapws/iapws97.py b/iapws/iapws97.py index 9e4c62d..e659a10 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -4714,8 +4714,10 @@ def fill(self, fase, estado): fase.n = None def derivative(self, z, x, y, fase): - """Wrapper derivative for custom derived properties - where x, y, z can be: P, T, v, u, h, s, g, a""" + """ + Wrapper derivative for custom derived properties + where x, y, z can be: P, T, v, u, h, s, g, a + """ return deriv_G(self, z, x, y, fase) From 0b41ec6acaa8d743f2740f516668db3611e69ac7 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 17:44:13 -0500 Subject: [PATCH 018/102] Correct flake8 D204 complaints. D204 1 blank line required after class docstring --- iapws/_utils.py | 1 + iapws/ammonia.py | 1 + iapws/humidAir.py | 3 +++ iapws/iapws08.py | 1 + iapws/iapws95.py | 8 ++++++++ iapws/iapws97.py | 6 ++++++ test.py | 1 + 7 files changed, 21 insertions(+) diff --git a/iapws/_utils.py b/iapws/_utils.py index 868982f..2731970 100644 --- a/iapws/_utils.py +++ b/iapws/_utils.py @@ -63,6 +63,7 @@ def getphase(Tc, Pc, T, P, x, region): class _fase(object): """Class to implement a null phase""" + v = None rho = None diff --git a/iapws/ammonia.py b/iapws/ammonia.py index 660e954..b645d06 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -30,6 +30,7 @@ class NH3(MEoS): R134a, R152a, and R123. Springer-Verlag, Berlin, 1994. http://doi.org/10.1007/978-3-642-79400-1 """ + name = "ammonia" CASNumber = "7664-41-7" formula = "NH3" diff --git a/iapws/humidAir.py b/iapws/humidAir.py index 74de3c2..d657c5d 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -226,6 +226,7 @@ class MEoSBlend(MEoS): Special meos class to implement pseudocomponent blend and defining its ancillary dew and bubble point """ + @classmethod def _dewP(cls, T): """Using ancillary equation return the pressure of dew point""" @@ -267,6 +268,7 @@ class Air(MEoSBlend): 2000 K at Pressures to 2000 MPa. J. Phys. Chem. Ref. Data 29, 331 (2000). http://dx.doi.org/10.1063/1.1285884 """ + name = "air" CASNumber = "1" formula = "N2+Ar+O2" @@ -568,6 +570,7 @@ class HumidAir(object): * HR: Humidity ratio, [-] * RH: Relative humidity, [-] """ + kwargs = {"T": 0.0, "P": 0.0, "rho": 0.0, diff --git a/iapws/iapws08.py b/iapws/iapws08.py index e417cb1..74d8a10 100644 --- a/iapws/iapws08.py +++ b/iapws/iapws08.py @@ -161,6 +161,7 @@ class SeaWater(object): >>> salt.haline 0.7311487666026304 """ + kwargs = {"T": 0.0, "P": 0.0, "S": None, diff --git a/iapws/iapws95.py b/iapws/iapws95.py index e6b5f03..f49eefc 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -368,6 +368,7 @@ class MEoS(_fase): * invT: Negative reciprocal temperature, [1/K] * hInput: Specific heat input, [kJ/kg] """ + CP = None _Pv = None _rhoL = None @@ -2329,6 +2330,7 @@ class IAPWS95(MEoS): IAPWS, Revised Advisory Note No. 3: Thermodynamic Derivatives from IAPWS Formulations, http://www.iapws.org/relguide/Advise3.pdf """ + name = "water" CASNumber = "7732-18-5" formula = "H2O" @@ -2628,30 +2630,35 @@ def _surface(self, T): class IAPWS95_PT(IAPWS95): """Derivated class for direct P and T input""" + def __init__(self, P, T): IAPWS95.__init__(self, T=T, P=P) class IAPWS95_Ph(IAPWS95): """Derivated class for direct P and h input""" + def __init__(self, P, h): IAPWS95.__init__(self, P=P, h=h) class IAPWS95_Ps(IAPWS95): """Derivated class for direct P and s input""" + def __init__(self, P, s): IAPWS95.__init__(self, P=P, s=s) class IAPWS95_Px(IAPWS95): """Derivated class for direct P and v input""" + def __init__(self, P, x): IAPWS95.__init__(self, P=P, x=x) class IAPWS95_Tx(IAPWS95): """Derivated class for direct T and x input""" + def __init__(self, T, x): IAPWS95.__init__(self, T=T, x=x) @@ -2674,6 +2681,7 @@ class D2O(MEoS): IAPWS, Revised Advisory Note No. 3: Thermodynamic Derivatives from IAPWS Formulations, http://www.iapws.org/relguide/Advise3.pdf """ + name = "heavy water" CASNumber = "7789-20-0" formula = "D2O" diff --git a/iapws/iapws97.py b/iapws/iapws97.py index e659a10..34a292b 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -4314,6 +4314,7 @@ class IAPWS97(object): >>> water.cp0, water.cv0, water.h0, water.s0, water.w0 1.8714 1.4098 2594.66 9.471 444.93 """ + kwargs = {"T": 0.0, "P": 0.0, "x": None, @@ -4723,29 +4724,34 @@ def derivative(self, z, x, y, fase): class IAPWS97_PT(IAPWS97): """Derivated class for direct P and T input""" + def __init__(self, P, T): IAPWS97.__init__(self, T=T, P=P) class IAPWS97_Ph(IAPWS97): """Derivated class for direct P and h input""" + def __init__(self, P, h): IAPWS97.__init__(self, P=P, h=h) class IAPWS97_Ps(IAPWS97): """Derivated class for direct P and s input""" + def __init__(self, P, s): IAPWS97.__init__(self, P=P, s=s) class IAPWS97_Px(IAPWS97): """Derivated class for direct P and x input""" + def __init__(self, P, x): IAPWS97.__init__(self, P=P, x=x) class IAPWS97_Tx(IAPWS97): """Derivated class for direct T and x input""" + def __init__(self, T, x): IAPWS97.__init__(self, T=T, x=x) diff --git a/test.py b/test.py index 38e7e2c..f90c5e2 100644 --- a/test.py +++ b/test.py @@ -42,6 +42,7 @@ class Test(unittest.TestCase): Global unittest for module Run for python2 and python3 before to release distribution """ + def test_Helmholtz(self): """Table 6 from IAPWS95, pag 14""" T = 500 From 4ce007857cd668f952b1765db092f6a943a8418a Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 17:50:52 -0500 Subject: [PATCH 019/102] Correct flake8 D101 complaints. D101 Missing docstring in public class Perhaps a better class documentation string is required? --- iapws/ammonia.py | 1 + 1 file changed, 1 insertion(+) diff --git a/iapws/ammonia.py b/iapws/ammonia.py index b645d06..60dcbcc 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -205,6 +205,7 @@ def _thermo(self, rho, T, fase): class H2ONH3(object): + """Ammonia-water mixtures.""" # TODO: Add equilibrium routine From 9fb940cb722877d2867b70add4cdd574cf127d2c Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 17:54:42 -0500 Subject: [PATCH 020/102] Correct flake8 D104 complaints. D104 Missing docstring in public package This is another case where perhaps a more descriptive doc string would be appropriate, but I don't know exactly what to say here. --- iapws/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/iapws/__init__.py b/iapws/__init__.py index 872e6ae..5140f32 100644 --- a/iapws/__init__.py +++ b/iapws/__init__.py @@ -1,5 +1,6 @@ #!/usr/bin/python # -*- coding: utf-8 -*- +"""International Association for the Properties of Water and Steam (IAPWS).""" import os From 8cf2c1cd5c2333e7d05b84142b9c19202bbe8003 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 18:07:27 -0500 Subject: [PATCH 021/102] Correct flake8 D102 complaints. D102 Missing docstring in public method --- iapws/iapws97.py | 3 +++ test.py | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/iapws/iapws97.py b/iapws/iapws97.py index 34a292b..4b25a52 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -4330,6 +4330,7 @@ def __init__(self, **kwargs): self.__call__(**kwargs) def __call__(self, **kwargs): + """Invoke the solver.""" self.kwargs.update(kwargs) if self.calculable: @@ -4361,6 +4362,7 @@ def calculable(self): return self._thermo def calculo(self): + """Calculate procedure""" propiedades = None args = (self.kwargs[self._thermo[0]], self.kwargs[self._thermo[1]]) if self._thermo == "TP": @@ -4667,6 +4669,7 @@ def funcion(rho): self.Svap = vapor["s"]-liquido["s"] def fill(self, fase, estado): + """Fill phase properties""" fase.v = estado["v"] fase.rho = 1/fase.v diff --git a/test.py b/test.py index f90c5e2..44d4040 100644 --- a/test.py +++ b/test.py @@ -1224,6 +1224,7 @@ def test_IAPWS95_custom(self): self.assertRaises(NotImplementedError, IAPWS95, **{"P": 25, "x": 1}) def test_D2O(self): + """Tables 6-8, page 12-13.""" # Table 6, pag 12""" fluid = D2O() @@ -2091,6 +2092,7 @@ def test_critNaCl(self): self.assertRaises(NotImplementedError, _critNaCl, 0.2) def test_Henry(self): + """Table 6, Henry constants.""" # Table 6 for Henry constants self.assertRaises(NotImplementedError, _Henry, *(300, "He", "He")) self.assertRaises(NotImplementedError, _Henry, *(300, "SF6", "D2O")) @@ -2276,6 +2278,7 @@ def xest_Conductivity(self): self.assertEqual(round(_Conductivity(1100, 473.15), 9), 22.8e-6) def test_virial(self): + """Tables 7 & 8, page 10""" # Table 7, page 10 st = _virial(200) self.assertEqual(round(st["Baa"], 13), -0.392722567e-4) @@ -2317,6 +2320,7 @@ def test_virial(self): self.assertRaises(NotImplementedError, _fugacity, *(190, 1, 0.1)) def test_Air(self): + """Tables A1 & A2, page 363 & 366.""" # Table A1, Pag 363 self.assertEqual(round(Air._bubbleP(59.75), 6), 0.005265) self.assertEqual(round(Air._bubbleP(59.75), 6), 0.005265) @@ -2690,6 +2694,7 @@ def test_Ammonia(self): self.assertWarns(Warning, st._thermo, *(235, st.Tc, st)) def test_AmmoniaVisco(self): + """Appendix II & III, page 1664 & 1667.""" # Appendix II, pag 1664 st = NH3(T=680, P=0.1) self.assertEqual(round(st.mu*1e6, 2), 24.66) @@ -2721,7 +2726,7 @@ def test_AmmoniaVisco(self): self.assertEqual(round(st.Liquid.mu*1e6, 2), 39.20) def test_nh3h2o(self): - + """Test outstanding problems in H2ONH3.""" # Range of validity Tt1 = Ttr(0) Tt2 = Ttr(0.5) From 73e0b40507d06e0daf25ef509fcc64156d2afde3 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 18:12:09 -0500 Subject: [PATCH 022/102] Correct flake8 E241 complaint. E241 multiple spaces after ',' --- iapws/iapws97.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iapws/iapws97.py b/iapws/iapws97.py index 4b25a52..9a3a4e0 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -4021,7 +4021,7 @@ def _Bound_hs(h, s): """ region = None s13 = _Region1(623.15, 100)["s"] - s13s = _Region1(623.15, Ps_623)["s"] + s13s = _Region1(623.15, Ps_623)["s"] sTPmax = _Region2(1073.15, 100)["s"] s2ab = _Region2(1073.15, 4)["s"] From 09dd37f24b04e9a3f8562ed35e80240b9da19f41 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 18:28:58 -0500 Subject: [PATCH 023/102] Correct flake8 E302 complaints. E302 expected 2 blank lines, found 1 --- iapws/iapws08.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iapws/iapws08.py b/iapws/iapws08.py index 74d8a10..a401426 100644 --- a/iapws/iapws08.py +++ b/iapws/iapws08.py @@ -625,6 +625,7 @@ def _ThCond_SeaWater(T, P, S): DL = a*(1000*S)**(1+b) return DL + def _Tension_SeaWater(T, S): """Equation for the surface tension of seawater @@ -671,6 +672,7 @@ def _Tension_SeaWater(T, S): sigma = sw*(1+3.766e-1*S+2.347e-3*S*(T-273.15)) return sigma + def _solNa2SO4(T, mH2SO4, mNaCl): """Equation for the solubility of sodium sulfate in aqueous mixtures of sodium chloride and sulfuric acid From 38e487cbe525daccf24ba9ecd26d9e75e1bd4172 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 18:43:02 -0500 Subject: [PATCH 024/102] Mark scripts executable when they can be run from command line. --- plots.py | 0 setup.py | 0 test.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 plots.py mode change 100644 => 100755 setup.py mode change 100644 => 100755 test.py diff --git a/plots.py b/plots.py old mode 100644 new mode 100755 diff --git a/setup.py b/setup.py old mode 100644 new mode 100755 diff --git a/test.py b/test.py old mode 100644 new mode 100755 From 08c6803c5c1e3b16d454ceb5d1f59b927f5fa00e Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 19:58:04 -0500 Subject: [PATCH 025/102] Some initial mypy changes to reduce error spew. All conditional function variants must have identical signatures Mypy doesn't like to have the same symbol declared with different types, even if they're in differen conditional scopes. --- iapws/humidAir.py | 11 +++-- iapws/iapws95.py | 116 ++++++++++++++++++++++++---------------------- iapws/iapws97.py | 31 +++++++------ 3 files changed, 83 insertions(+), 75 deletions(-) diff --git a/iapws/humidAir.py b/iapws/humidAir.py index d657c5d..1803737 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -16,6 +16,7 @@ from __future__ import division from math import exp, log, pi, atan import warnings +from typing import Tuple from scipy.optimize import fsolve @@ -642,15 +643,15 @@ def calculo(self): # Thermodynamic definition if self._mode == "TP": - def f(rho): + def rho_func(rho: float) -> float: fav = self._fav(T, rho, A) return rho**2*fav["fird"]/1000-P - rho = fsolve(f, 1)[0] + rho = fsolve(rho_func, 1)[0] elif self._mode == "Prho": - def f(T): + def t_func(T: float) -> float: fav = self._fav(T, rho, A) return rho**2*fav["fird"]/1000-P - T = fsolve(f, 300)[0] + T = fsolve(t_func, 300)[0] # General calculation procedure fav = self._fav(T, rho, A) @@ -718,7 +719,7 @@ def _eq(self, T, P): water = IAPWS95(T=T, P=P) gw = water.g - def f(parr): + def f(parr: Tuple[float, float]) -> Tuple[float, float]: rho, a = parr if a > 1: a = 1 diff --git a/iapws/iapws95.py b/iapws/iapws95.py index f49eefc..bb47d4c 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -17,6 +17,7 @@ from numpy import exp, log, ndarray from scipy.optimize import fsolve +from typing import Tuple from .iapws97 import _TSat_P, IAPWS97 from ._iapws import M, Tc, Pc, rhoc, Tc_D2O, Pc_D2O, rhoc_D2O @@ -530,7 +531,7 @@ def calculo(self): else: rhoo = self.rhoc*3 - def f(rho): + def rho_func(rho: float) -> float: delta = rho/rhoc tau = Tc/T @@ -538,7 +539,7 @@ def f(rho): Po = (1+delta*fird)*self.R*T*rho return Po-P*1000 - rho = fsolve(f, rhoo)[0] + rho = fsolve(rho_func, rhoo)[0] # Calculate quality if T > self.Tc: @@ -559,7 +560,7 @@ def f(rho): ideal = self._phi0(tau, 1) fiot = ideal["fiot"] - def f(rho): + def rho_func(rho: float) -> float: delta = rho/rhoc fird = _phird(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) @@ -568,7 +569,7 @@ def f(rho): if T >= self.Tc: rhoo = self.rhoc - rho = fsolve(f, rhoo)[0] + rho = fsolve(rho_func, rhoo)[0] else: x0 = self.kwargs["x0"] rhov = self._Vapor_Density(T) @@ -596,12 +597,12 @@ def f(rho): rhoo = rhov else: rhoo = rhol - rho = fsolve(f, rhoo)[0] + rho = fsolve(rho_func, rhoo)[0] elif self._mode == "Ts": tau = Tc/T - def f(rho): + def rho_func(rho: float) -> float: if rho < 0: rho = 1e-20 delta = rho/rhoc @@ -616,7 +617,7 @@ def f(rho): if T >= self.Tc: rhoo = self.rhoc - rho = fsolve(f, rhoo)[0] + rho = fsolve(rho_func, rhoo)[0] else: rhov = self._Vapor_Density(T) rhol = self._Liquid_Density(T) @@ -649,14 +650,14 @@ def f(rho): rhoo = rhov else: rhoo = rhol - rho = fsolve(f, rhoo)[0] + rho = fsolve(rho_func, rhoo)[0] elif self._mode == "Tu": tau = Tc/T ideal = self._phi0(tau, 1) fiot = ideal["fiot"] - def f(rho): + def rho_func(rho: float) -> float: delta = rho/rhoc fird = _phird(tau, delta, self._constants) @@ -668,7 +669,7 @@ def f(rho): if T >= self.Tc: rhoo = self.rhoc - rho = fsolve(f, rhoo)[0] + rho = fsolve(rho_func, rhoo)[0] else: rhov = self._Vapor_Density(T) rhol = self._Liquid_Density(T) @@ -700,24 +701,24 @@ def f(rho): rhoo = rhov else: rhoo = rhol - rho = fsolve(f, rhoo)[0] + rho = fsolve(rho_func, rhoo)[0] elif self._mode == "Prho": delta = rho/rhoc - def f(T): + def t_func(T: float) -> float: tau = Tc/T fird = _phird(tau, delta, self._constants) Po = (1+delta*fird)*self.R*T*rho return Po-P*1000 - T = fsolve(f, To)[0] + T = fsolve(t_func, To)[0] rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if T == To or rhov <= rho <= rhol: - def f(parr): + def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: T, rhol, rhog = parr tau = Tc/T deltaL = rhol/self.rhoc @@ -739,7 +740,7 @@ def f(parr): for to in [To, 300, 400, 500, 600]: rhoLo = self._Liquid_Density(to) rhoGo = self._Vapor_Density(to) - sol = fsolve(f, [to, rhoLo, rhoGo], full_output=True) + sol = fsolve(f3, [to, rhoLo, rhoGo], full_output=True) T, rhoL, rhoG = sol[0] x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) if sol[2] == 1 and 0 <= x <= 1 and \ @@ -755,7 +756,7 @@ def f(parr): liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 elif self._mode == "Ph": - def funcion(parr): + def f2(parr: Tuple[float, float]) -> Tuple[float, float]: rho, T = parr delta = rho/rhoc tau = Tc/T @@ -768,12 +769,13 @@ def funcion(parr): ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return Po-P*1000, ho-h - rho, T = fsolve(funcion, [rhoo, To]) + rho, T = fsolve(f2, [rhoo, To]) rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if rho == rhoo or rhov <= rho <= rhol: - def f(parr): + def f4(parr: Tuple[float, float, float, float]) \ + -> Tuple[float, float, float, float]: T, rhol, rhog, x = parr tau = Tc/T deltaL = rhol/self.rhoc @@ -804,7 +806,7 @@ def f(parr): for to in [To, 300, 400, 500, 600]: rLo = self._Liquid_Density(to) rGo = self._Vapor_Density(to) - sol = fsolve(f, [to, rLo, rGo, 0.5], full_output=True) + sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) T, rhoL, rhoG, x = sol[0] if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: @@ -825,7 +827,7 @@ def f(parr): x0 = None if x0 is None or x0 == 0 or x0 == 1: - def f(parr): + def f2(parr: Tuple[float, float]) -> Tuple[float, float]: rho, T = parr delta = rho/rhoc tau = Tc/T @@ -840,17 +842,17 @@ def f(parr): so = self.R*(tau*(fiot+firt)-fio-fir) return Po-P*1000, so-s - rho, T = fsolve(f, [rhoo, To]) + rho, T = fsolve(f2, [rhoo, To]) else: - def funcion(parr): + def f2(parr: Tuple[float, float]) -> Tuple[float, float]: rho, T = parr rhol, rhov, Ps = self._saturation(T) vapor = self._Helmholtz(rhov, T) liquido = self._Helmholtz(rhol, T) x = (1./rho-1/rhol)/(1/rhov-1/rhol) return Ps-P*1000, vapor["s"]*x+liquido["s"]*(1-x)-s - rho, T = fsolve(funcion, [2., 500.]) + rho, T = fsolve(f2, [2., 500.]) rhol, rhov, Ps = self._saturation(T) vapor = self._Helmholtz(rhov, T) liquido = self._Helmholtz(rhol, T) @@ -859,7 +861,7 @@ def funcion(parr): x = (s-sl)/(sv-sl) elif self._mode == "Pu": - def f(parr): + def f2(parr: Tuple[float, float]) -> Tuple[float, float]: rho, T = parr delta = rho/rhoc tau = Tc/T @@ -872,13 +874,14 @@ def f(parr): ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return ho-Po/rho-u, Po-P*1000 - sol = fsolve(f, [rhoo, To], full_output=True) + sol = fsolve(f2, [rhoo, To], full_output=True) rho, T = sol[0] rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if rho == rhoo or sol[2] != 1: - def f(parr): + def f4(parr: Tuple[float, float, float, float]) \ + -> Tuple[float, float, float, float]: T, rhol, rhog, x = parr tau = Tc/T deltaL = rhol/self.rhoc @@ -910,7 +913,7 @@ def f(parr): for to in [To, 300, 400, 500, 600]: rLo = self._Liquid_Density(to) rGo = self._Vapor_Density(to) - sol = fsolve(f, [to, rLo, rGo, 0.5], full_output=True) + sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) T, rhoL, rhoG, x = sol[0] if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: @@ -927,7 +930,7 @@ def f(parr): elif self._mode == "rhoh": delta = rho/rhoc - def f(T): + def t_func(T: float) -> float: tau = Tc/T ideal = self._phi0(tau, delta) @@ -937,11 +940,11 @@ def f(T): ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return ho-h - T = fsolve(f, To)[0] + T = fsolve(t_func, To)[0] rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if T == To or rhov <= rho <= rhol: - def f(parr): + def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: T, rhol, rhog = parr tau = Tc/T deltaL = rhol/self.rhoc @@ -969,7 +972,7 @@ def f(parr): for to in [To, 300, 400, 500, 600]: rhoLo = self._Liquid_Density(to) rhoGo = self._Vapor_Density(to) - sol = fsolve(f, [to, rhoLo, rhoGo], full_output=True) + sol = fsolve(f3, [to, rhoLo, rhoGo], full_output=True) T, rhoL, rhoG = sol[0] x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) if sol[2] == 1 and 0 <= x <= 1 and \ @@ -987,7 +990,7 @@ def f(parr): elif self._mode == "rhos": delta = rho/rhoc - def f(T): + def t_func(T: float) -> float: tau = Tc/T ideal = self._phi0(tau, delta) fio = ideal["fio"] @@ -997,12 +1000,12 @@ def f(T): so = self.R*(tau*(fiot+firt)-fio-fir) return so-s - T = fsolve(f, To)[0] + T = fsolve(t_func, To)[0] rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if T == To or rhov <= rho <= rhol: - def f(parr): + def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: T, rhol, rhog = parr tau = Tc/T deltaL = rhol/self.rhoc @@ -1034,7 +1037,7 @@ def f(parr): for to in [To, 300, 400, 500, 600]: rhoLo = self._Liquid_Density(to) rhoGo = self._Vapor_Density(to) - sol = fsolve(f, [to, rhoLo, rhoGo], full_output=True) + sol = fsolve(f3, [to, rhoLo, rhoGo], full_output=True) T, rhoL, rhoG = sol[0] x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) if sol[2] == 1 and 0 <= x <= 1 and \ @@ -1052,7 +1055,7 @@ def f(parr): elif self._mode == "rhou": delta = rho/rhoc - def f(T): + def t_func(T: float) -> float: tau = Tc/T ideal = self._phi0(tau, delta) @@ -1063,11 +1066,11 @@ def f(T): ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return ho-Po/rho-u - T = fsolve(f, To)[0] + T = fsolve(t_func, To)[0] rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if T == To or rhov <= rho <= rhol: - def f(parr): + def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: T, rhol, rhog = parr tau = Tc/T deltaL = rhol/self.rhoc @@ -1098,7 +1101,7 @@ def f(parr): for to in [To, 300, 400, 500, 600]: rhoLo = self._Liquid_Density(to) rhoGo = self._Vapor_Density(to) - sol = fsolve(f, [to, rhoLo, rhoGo], full_output=True) + sol = fsolve(f3, [to, rhoLo, rhoGo], full_output=True) T, rhoL, rhoG = sol[0] x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) if sol[2] == 1 and 0 <= x <= 1 and \ @@ -1114,7 +1117,7 @@ def f(parr): liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 elif self._mode == "hs": - def f(parr): + def f2(parr: Tuple[float, float]) -> Tuple[float, float]: rho, T = parr delta = rho/rhoc tau = Tc/T @@ -1129,12 +1132,13 @@ def f(parr): so = self.R*(tau*(fiot+firt)-fio-fir) return ho-h, so-s - rho, T = fsolve(f, [rhoo, To]) + rho, T = fsolve(f2, [rhoo, To]) rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if rhov <= rho <= rhol: - def f(parr): + def f4(parr: Tuple[float, float, float, float]) -> \ + Tuple[float, float, float, float]: T, rhol, rhog, x = parr tau = Tc/T deltaL = rhol/self.rhoc @@ -1168,7 +1172,7 @@ def f(parr): for to in [To, 300, 400, 500, 600]: rLo = self._Liquid_Density(to) rGo = self._Vapor_Density(to) - sol = fsolve(f, [to, rLo, rGo, 0.5], full_output=True) + sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) T, rhoL, rhoG, x = sol[0] if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: @@ -1183,7 +1187,7 @@ def f(parr): liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 elif self._mode == "hu": - def f(parr): + def f2(parr: Tuple[float, float]) -> Tuple[float, float]: rho, T = parr delta = rho/rhoc tau = Tc/T @@ -1197,13 +1201,14 @@ def f(parr): return ho-Po/rho-u, ho-h - sol = fsolve(f, [rhoo, To], full_output=True) + sol = fsolve(f2, [rhoo, To], full_output=True) rho, T = sol[0] rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if sol[2] != 1 or rhov <= rho <= rhol: - def f(parr): + def f4(parr: Tuple[float, float, float, float]) -> \ + Tuple[float, float, float, float]: T, rhol, rhog, x = parr tau = Tc/T deltaL = rhol/self.rhoc @@ -1237,7 +1242,7 @@ def f(parr): for to in [To, 300, 400, 500, 600]: rLo = self._Liquid_Density(to) rGo = self._Vapor_Density(to) - sol = fsolve(f, [to, rLo, rGo, 0.5], full_output=True) + sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) T, rhoL, rhoG, x = sol[0] if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: @@ -1252,7 +1257,7 @@ def f(parr): liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 elif self._mode == "su": - def f(parr): + def f2(parr: Tuple[float, float]) -> Tuple[float, float]: rho, T = parr delta = rho/rhoc tau = Tc/T @@ -1268,13 +1273,14 @@ def f(parr): Po = (1+delta*fird)*self.R*T*rho return ho-Po/rho-u, so-s - sol = fsolve(f, [rhoo, To], full_output=True) + sol = fsolve(f2, [rhoo, To], full_output=True) rho, T = sol[0] rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if sol[2] != 1 or rhov <= rho <= rhol: - def f(parr): + def f4(parr: Tuple[float, float, float, float]) -> \ + Tuple[float, float, float, float]: T, rhol, rhog, x = parr tau = Tc/T deltaL = rhol/self.rhoc @@ -1313,7 +1319,7 @@ def f(parr): for to in [To, 300, 400, 500, 600]: rLo = self._Liquid_Density(to) rGo = self._Vapor_Density(to) - sol = fsolve(f, [to, rLo, rGo, 0.5], full_output=True) + sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) T, rhoL, rhoG, x = sol[0] if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: @@ -1371,7 +1377,7 @@ def f(parr): raise NotImplementedError("Incoming out of bound") # Iterate over saturation routine to get T - def f(T): + def t_func(T: float) -> float: rhol = self._Liquid_Density(T) rhog = self._Vapor_Density(T) @@ -1392,7 +1398,7 @@ def f(T): To = _TSat_P(P) else: To = (self.Tc+self.Tt)/2 - T = fsolve(f, To)[0] + T = fsolve(t_func, To)[0] rhol, rhov, Ps = self._saturation(T) vapor = self._Helmholtz(rhov, T) liquido = self._Helmholtz(rhol, T) @@ -1572,7 +1578,7 @@ def _saturation(self, T): rhoLo = self._Liquid_Density(T) rhoGo = self._Vapor_Density(T) - def f(parr): + def f2(parr: Tuple[float, float]) -> Tuple[float, float]: rhol, rhog = parr deltaL = rhol/rhoc deltaG = rhog/rhoc @@ -1586,7 +1592,7 @@ def f(parr): Kv = deltaG*phirdG+phirG+log(deltaG) return Kv-Kl, Jv-Jl - rhoL, rhoG = fsolve(f, [rhoLo, rhoGo]) + rhoL, rhoG = fsolve(f2, [rhoLo, rhoGo]) if rhoL == rhoG: Ps = self.Pc else: diff --git a/iapws/iapws97.py b/iapws/iapws97.py index 9a3a4e0..d07a22f 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -84,6 +84,7 @@ from __future__ import division from math import sqrt, log, exp +from typing import Tuple from scipy.optimize import fsolve, newton @@ -4160,7 +4161,7 @@ def _Bound_hs(h, s): if not region and \ _Region5(1073.15, 50)["s"] < s <= _Region5(2273.15, Pmin)["s"] \ and _Region5(1073.15, 50)["h"] < h <= _Region5(2273.15, Pmin)["h"]: - def funcion(par): + def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return (_Region5(par[0], par[1])["h"]-h, _Region5(par[0], par[1])["s"]-s) T, P = fsolve(funcion, [1400, 1]) @@ -4378,9 +4379,9 @@ def calculo(self): else: vo = _Backward3_v_PT(P, T) - def funcion(rho): + def rho_funcion(rho: float) -> float: return _Region3(rho, self.kwargs["T"])["P"]-P - rho = newton(funcion, 1/vo) + rho = newton(rho_funcion, 1/vo) propiedades = _Region3(rho, T) elif region == 5: propiedades = _Region5(T, P) @@ -4402,7 +4403,7 @@ def funcion(rho): vo = _Backward3_v_Ph(P, h) To = _Backward3_T_Ph(P, h) - def funcion(par): + def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return (_Region3(par[0], par[1])["h"]-h, _Region3(par[0], par[1])["P"]-P) rho, T = fsolve(funcion, [1/vo, To]) @@ -4418,7 +4419,7 @@ def funcion(par): vo = _Backward3_v_Ph(P, h) To = _Backward3_T_Ph(P, h) - def funcion(par): + def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return (_Region3(par[0], par[1])["h"]-h, _Region3(par[0], par[1])["P"]-P) rho, T = fsolve(funcion, [1/vo, To]) @@ -4444,7 +4445,7 @@ def funcion(par): vo = _Backward3_v_Ps(P, s) To = _Backward3_T_Ps(P, s) - def funcion(par): + def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return (_Region3(par[0], par[1])["s"]-s, _Region3(par[0], par[1])["P"]-P) rho, T = fsolve(funcion, [1/vo, To]) @@ -4460,7 +4461,7 @@ def funcion(par): vo = _Backward3_v_Ps(P, s) To = _Backward3_T_Ps(P, s) - def funcion(par): + def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return (_Region3(par[0], par[1])["s"]-s, _Region3(par[0], par[1])["P"]-P) rho, T = fsolve(funcion, [1/vo, To]) @@ -4478,7 +4479,7 @@ def funcion(par): Po = _Backward1_P_hs(h, s) To = _Backward1_T_Ph(Po, h) - def funcion(par): + def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return (_Region1(par[0], par[1])["h"]-h, _Region1(par[0], par[1])["s"]-s) T, P = fsolve(funcion, [To, Po]) @@ -4487,7 +4488,7 @@ def funcion(par): Po = _Backward2_P_hs(h, s) To = _Backward2_T_Ph(Po, h) - def funcion(par): + def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return (_Region2(par[0], par[1])["h"]-h, _Region2(par[0], par[1])["s"]-s) T, P = fsolve(funcion, [To, Po]) @@ -4497,7 +4498,7 @@ def funcion(par): vo = _Backward3_v_Ph(P, h) To = _Backward3_T_Ph(P, h) - def funcion(par): + def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return (_Region3(par[0], par[1])["h"]-h, _Region3(par[0], par[1])["s"]-s) rho, T = fsolve(funcion, [1/vo, To]) @@ -4511,7 +4512,7 @@ def funcion(par): if To < 273.15 or To > Tc: To = 300 - def funcion(par): + def funcion2(par: Tuple[float, float]) -> Tuple[float, float]: if par[1] < 0: par[1] = 0 elif par[1] > 1: @@ -4530,7 +4531,7 @@ def funcion(par): sv = vapor["s"] return (hv*par[1]+hl*(1-par[1])-h, sv*par[1]+sl*(1-par[1])-s) - T, x = fsolve(funcion, [To, 0.5]) + T, x = fsolve(funcion2, [To, 0.5]) P = _PSat_T(T) if Pt <= P < Pc and 0 < x < 1: @@ -4538,7 +4539,7 @@ def funcion(par): elif Pt <= P <= Ps_623 and x == 0: propiedades = _Region1(T, P) elif region == 5: - def funcion(par): + def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return (_Region5(par[0], par[1])["h"]-h, _Region5(par[0], par[1])["s"]-s) T, P = fsolve(funcion, [1400, 1]) @@ -4556,10 +4557,10 @@ def funcion(par): elif Pt <= P <= Ps_623 and x == 1: propiedades = _Region2(T, P) elif Ps_623 < P < Pc and x in (0, 1): - def funcion(rho): + def rho_funcion(rho: float) -> float: return _Region3(rho, T)["P"]-P rhoo = 1./_Backward3_sat_v_P(P, T, x) - rho = fsolve(funcion, rhoo)[0] + rho = fsolve(rho_funcion, rhoo)[0] propiedades = _Region3(rho, T) elif P == Pc and 0 <= x <= 1: propiedades = _Region3(rhoc, Tc) From 38ae29f51ab0943738a06d2e64ed6cb4a93d7abb Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 20:23:25 -0500 Subject: [PATCH 026/102] Draw attention to possible bug found by mypy. iapws/iapws97.py:4520: error: Unsupported target for indexed assignment ("Tuple[float, float]") iapws/iapws97.py:4522: error: Unsupported target for indexed assignment ("Tuple[float, float]") Because tuples are not modifable, the previously code generated mypy errors despite being what I thought was the intended API. I thought that I could modify the code to remove the stealthy update of the CALLERS par list, but it trurns out that this change is required, and causes tests to fail. Was this update intentional? If so, perhaps a comment is appropriate? If not, I think this is a bug. --- iapws/iapws97.py | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/iapws/iapws97.py b/iapws/iapws97.py index d07a22f..119c327 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -84,7 +84,7 @@ from __future__ import division from math import sqrt, log, exp -from typing import Tuple +from typing import Tuple, List from scipy.optimize import fsolve, newton @@ -4512,25 +4512,38 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: if To < 273.15 or To > Tc: To = 300 - def funcion2(par: Tuple[float, float]) -> Tuple[float, float]: - if par[1] < 0: - par[1] = 0 - elif par[1] > 1: - par[1] = 1 - if par[0] < 273.15: - par[0] = 273.15 - elif par[0] > Tc: - par[0] = Tc - - Po = _PSat_T(par[0]) - liquid = _Region1(par[0], Po) - vapor = _Region2(par[0], Po) + def funcion2(par: List[float]) -> Tuple[float, float]: + # This passes tests, but these assignments modify the CALLERS + # par tuple, instead of our copy. Was that intended? + if True: + if par[1] < 0: + par[1] = 0 + elif par[1] > 1: + par[1] = 1 + pp1 = par[1] + # And this does not. + else: + pp1 = par[1] + if pp1 < 0: + pp1 = 0 + elif pp1 > 1: + pp1 = 1 + + pp0 = par[0] + if pp0 < 273.15: + pp0 = 273.15 + elif pp0 > Tc: + pp0 = Tc + + Po = _PSat_T(pp0) + liquid = _Region1(pp0, Po) + vapor = _Region2(pp0, Po) hl = liquid["h"] sl = liquid["s"] hv = vapor["h"] sv = vapor["s"] - return (hv*par[1]+hl*(1-par[1])-h, - sv*par[1]+sl*(1-par[1])-s) + return (hv*pp1+hl*(1-pp1)-h, + sv*pp1+sl*(1-pp1)-s) T, x = fsolve(funcion2, [To, 0.5]) P = _PSat_T(T) From 23e9af2125a1dc6fb706fbe3a5dfe8b386e83b16 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 20:37:58 -0500 Subject: [PATCH 027/102] Correct unfortunate interaction of flake8 and mypy. The line breaks that make sense to me don't actually work. This solution is rather ugly but it makes both mypy and flake8 happy. --- iapws/iapws95.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/iapws/iapws95.py b/iapws/iapws95.py index bb47d4c..f84c843 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -774,8 +774,8 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: rhov = self._Vapor_Density(T) if rho == rhoo or rhov <= rho <= rhol: - def f4(parr: Tuple[float, float, float, float]) \ - -> Tuple[float, float, float, float]: + def f4(parr: Tuple[float, float, float, float]) -> Tuple[ + float, float, float, float]: T, rhol, rhog, x = parr tau = Tc/T deltaL = rhol/self.rhoc @@ -880,8 +880,8 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: rhov = self._Vapor_Density(T) if rho == rhoo or sol[2] != 1: - def f4(parr: Tuple[float, float, float, float]) \ - -> Tuple[float, float, float, float]: + def f4(parr: Tuple[float, float, float, float]) -> Tuple[ + float, float, float, float]: T, rhol, rhog, x = parr tau = Tc/T deltaL = rhol/self.rhoc @@ -1137,8 +1137,8 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: rhov = self._Vapor_Density(T) if rhov <= rho <= rhol: - def f4(parr: Tuple[float, float, float, float]) -> \ - Tuple[float, float, float, float]: + def f4(parr: Tuple[float, float, float, float]) -> Tuple[ + float, float, float, float]: T, rhol, rhog, x = parr tau = Tc/T deltaL = rhol/self.rhoc @@ -1207,8 +1207,8 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: rhov = self._Vapor_Density(T) if sol[2] != 1 or rhov <= rho <= rhol: - def f4(parr: Tuple[float, float, float, float]) -> \ - Tuple[float, float, float, float]: + def f4(parr: Tuple[float, float, float, float]) -> Tuple[ + float, float, float, float]: T, rhol, rhog, x = parr tau = Tc/T deltaL = rhol/self.rhoc @@ -1279,8 +1279,8 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: rhov = self._Vapor_Density(T) if sol[2] != 1 or rhov <= rho <= rhol: - def f4(parr: Tuple[float, float, float, float]) -> \ - Tuple[float, float, float, float]: + def f4(parr: Tuple[float, float, float, float]) -> Tuple[ + float, float, float, float]: T, rhol, rhog, x = parr tau = Tc/T deltaL = rhol/self.rhoc From 0552aa8a5957a3b6a574bed54a6299f7b69d0246 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 21:00:11 -0500 Subject: [PATCH 028/102] Specify types for member of MeOS that weren't declared. Or were declared with types (None) that didn't match the types on the Derived classes. The mypy errors were roughly: error: "MEoS" has no attribute "rhoc" error: "MEoS" has no attribute "_constants" error: Incompatible types in assignment (expression has type "Dict[str, List[float]]", base class "MEoS" defined the type as "None") --- iapws/iapws95.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/iapws/iapws95.py b/iapws/iapws95.py index f84c843..c2c53a4 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -17,7 +17,7 @@ from numpy import exp, log, ndarray from scipy.optimize import fsolve -from typing import Tuple +from typing import Tuple, Dict, Optional, Union, List from .iapws97 import _TSat_P, IAPWS97 from ._iapws import M, Tc, Pc, rhoc, Tc_D2O, Pc_D2O, rhoc_D2O @@ -371,9 +371,9 @@ class MEoS(_fase): """ CP = None - _Pv = None - _rhoL = None - _rhoG = None + _Pv: Optional[Dict[str, Union[int, List[float]]]] = None + _rhoL: Optional[Dict[str, Union[int, List[float]]]] = None + _rhoG: Optional[Dict[str, Union[int, List[float]]]] = None kwargs = {"T": 0.0, "P": 0.0, @@ -390,6 +390,13 @@ class MEoS(_fase): status = 0 msg = "Undefined" + # These are used in MeOS but are NOT actually defined by the + # class. They have to be defined by one of the subclasses which + # is a little messy. By statically typing them here, we at least + # let mypy know that they're supposed to be set... + rhoc: float + _constants: Dict[str, Union[float, List[float]]] + def __init__(self, **kwargs): """Constructor, define common constant and initinialice kwargs""" self.R = self._constants["R"]/self._constants.get("M", self.M) From 3b5bda045163205fb08a472ded94e8532bb62a7b Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 21:25:59 -0500 Subject: [PATCH 029/102] Apply some types in plots.py and docs/conf.py to make mypy happy. The types on np.linspace probably shouldn't be needed if we had proper stubs. The remaining mypy errors are about missing stubs form numpy, scipy, and matplotlib. --- docs/conf.py | 3 ++- plots.py | 29 ++++++++++++++++------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 95ad648..3c27383 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -16,6 +16,7 @@ import sys import os +from typing import Dict # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -224,7 +225,7 @@ # -- Options for LaTeX output --------------------------------------------- -latex_elements = { +latex_elements: Dict[str, str] = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', diff --git a/plots.py b/plots.py index daf3692..6f8287c 100755 --- a/plots.py +++ b/plots.py @@ -5,6 +5,7 @@ from math import pi, atan, log import matplotlib.pyplot as plt import numpy as np +from typing import Dict, List, Any import iapws from iapws._iapws import Pt, Pc, Tc @@ -144,7 +145,7 @@ # Calculate isoquality lines print("Calculating isoquality lines...") -Q = {} +Q: Dict[str, Dict[str, List[Any]]] = {} for q in isoq: Q["%s" % q] = {} txt = "x=%s" % q @@ -160,7 +161,7 @@ # Calculate isotherm lines if xAxis != "T" and yAxis != "T": print("Calculating isotherm lines...") - T_ = {} + T_: Dict[str, Dict[str, List[Any]]] = {} for T in isoT: T_["%s" % T] = {} print(" T=%sºC" % T) @@ -200,7 +201,7 @@ # Calculate isobar lines if xAxis != "P" and yAxis != "P": print("Calculating isobar lines...") - P_ = {} + P_: Dict[str, Dict[str, List[Any]]] = {} for P in isoP: print(" P=%sMPa" % P) P_["%s" % P] = {} @@ -240,7 +241,7 @@ # Calculate isoenthalpic lines if xAxis != "h" and yAxis != "h": print("Calculating isoenthalpic lines...") - H_ = {} + H_: Dict[str, Dict[str, List[Any]]] = {} for h in isoh: print(" h=%skJ/kg" % h) H_["%s" % h] = {} @@ -267,7 +268,7 @@ # Calculate isoentropic lines if xAxis != "s" and yAxis != "s": print("Calculating isoentropic lines...") - S_ = {} + S_: Dict[str, Dict[str, List[Any]]] = {} for s in isos: print(" s=%skJ/kgK" % s) S_["%s" % s] = {} @@ -296,10 +297,10 @@ print("Calculating isochor lines...") for v in isov: print(" v=%s" % v) - pts = [iapws.IAPWS95(T=t, v=v) for t in Tl] + pts95 = [iapws.IAPWS95(T=t, v=v) for t in Tl] x = [] y = [] - for p in pts: + for p in pts95: if p.status: x.append(p.__getattribute__(xAxis)) y.append(p.__getattribute__(yAxis)) @@ -310,17 +311,19 @@ if regionBoundary: # Boundary 1-3 Po = _PSat_T(623.15) - P = np.linspace(Po, 100, points) - pts = [fluid(P=p, T=623.15) for p in P] + # Mypy was confused about the np.linspace return type. + numpy_pressure_points: List[float] = np.linspace(Po, 100, points) + pts = [fluid(P=p, T=623.15) for p in numpy_pressure_points] x = [p.__getattribute__(xAxis) for p in pts] y = [p.__getattribute__(yAxis) for p in pts] plt.plot(x, y, **isosat_kw) # Boundary 2-3 - T = np.linspace(623.15, 863.15) - P = [_P23_T(t) for t in T] - P[-1] = 100 # Avoid round problem with value out of range > 100 MPa - pts = [fluid(P=p, T=t) for p, t in zip(P, T)] + # Mypy was confused about the np.linspace return type. + numpy_temp_points: List[float] = np.linspace(623.15, 863.15) + Ps = [_P23_T(t) for t in numpy_temp_points] + Ps[-1] = 100 # Avoid round problem with value out of range > 100 MPa + pts = [fluid(P=p, T=t) for p, t in zip(Ps, numpy_temp_points)] x = [p.__getattribute__(xAxis) for p in pts] y = [p.__getattribute__(yAxis) for p in pts] plt.plot(x, y, **isosat_kw) From 6f6236fb0c9892566441a1b0cd1ceab8de42e93a Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 13 Mar 2021 21:52:03 -0500 Subject: [PATCH 030/102] Convert R, Tref, and Rhoref to lists of length 1. This may be a controversial change, but for mypy to make much sense of the static types, we need _constants to be more stongly typed (not dependent on the key string). Perhaps there's something I can do to restore this later, but not right now wre' still getting static types. --- iapws/ammonia.py | 2 +- iapws/humidAir.py | 4 ++-- iapws/iapws95.py | 38 +++++++++++++++++++------------------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/iapws/ammonia.py b/iapws/ammonia.py index 60dcbcc..f8673c0 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -51,7 +51,7 @@ class NH3(MEoS): "ao_hyp": [], "hyp": []} _constants = { - "R": 8.314471, + "R": [8.314471], "nr1": [-0.1858814e01, 0.4554431e-1, 0.7238548, 0.1229470e-1, 0.2141882e-10], diff --git a/iapws/humidAir.py b/iapws/humidAir.py index 1803737..23c8b9b 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -295,8 +295,8 @@ class Air(MEoSBlend): } _constants = { - "R": 8.31451, - "Tref": 132.6312, "rhoref": 10.4477*Ma, + "R": [8.31451], + "Tref": [132.6312], "rhoref": [10.4477*Ma], "nr1": [0.118160747229, 0.713116392079, -0.161824192067e1, 0.714140178971e-1, -0.865421396646e-1, 0.134211176704, diff --git a/iapws/iapws95.py b/iapws/iapws95.py index c2c53a4..bd2ddae 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -26,7 +26,7 @@ from ._utils import _fase, getphase, deriv_H -def _phir(tau, delta, coef): +def _phir(tau: float, delta: float, coef: Dict[str, List[float]]) -> float: """Residual contribution to the adimensional free Helmholtz energy Parameters @@ -50,7 +50,7 @@ def _phir(tau, delta, coef): Scientific Use, September 2016, Table 5 http://www.iapws.org/relguide/IAPWS-95.html """ - fir = 0 + fir = 0.0 # Polinomial terms nr1 = coef.get("nr1", []) @@ -395,11 +395,11 @@ class MEoS(_fase): # is a little messy. By statically typing them here, we at least # let mypy know that they're supposed to be set... rhoc: float - _constants: Dict[str, Union[float, List[float]]] + _constants: Dict[str, List[float]] def __init__(self, **kwargs): """Constructor, define common constant and initinialice kwargs""" - self.R = self._constants["R"]/self._constants.get("M", self.M) + self.R = self._constants["R"][0]/self._constants.get("M", self.M) self.Zc = self.Pc/self.rhoc/self.R/self.Tc self.kwargs = MEoS.kwargs.copy() self.__call__(**kwargs) @@ -513,9 +513,9 @@ def calculo(self): To = 300 rhoo = 900 - self.R = self._constants["R"]/self._constants.get("M", self.M) - rhoc = self._constants.get("rhoref", self.rhoc) - Tc = self._constants.get("Tref", self.Tc) + self.R = self._constants["R"][0]/self._constants.get("M", self.M) + rhoc = self._constants.get("rhoref", [self.rhoc])[0] + Tc = self._constants.get("Tref", [self.Tc])[0] propiedades = None @@ -1575,8 +1575,8 @@ def derivative(self, z, x, y, fase): def _saturation(self, T): """Saturation calculation for two phase search""" - rhoc = self._constants.get("rhoref", self.rhoc) - Tc = self._constants.get("Tref", self.Tc) + rhoc = self._constants.get("rhoref", [self.rhoc])[0] + Tc = self._constants.get("Tref", [self.Tc])[0] if T > Tc: T = Tc @@ -1651,8 +1651,8 @@ def _Helmholtz(self, rho, T): rho = 1e-20 if T < 50: T = 50 - rhoc = self._constants.get("rhoref", self.rhoc) - Tc = self._constants.get("Tref", self.Tc) + rhoc = self._constants.get("rhoref", [self.rhoc])[0] + Tc = self._constants.get("Tref", [self.Tc])[0] delta = rho/rhoc tau = Tc/T ideal = self._phi0(tau, delta) @@ -1686,8 +1686,8 @@ def _Helmholtz(self, rho, T): def _prop0(self, rho, T): """Ideal gas properties""" - rhoc = self._constants.get("rhoref", self.rhoc) - Tc = self._constants.get("Tref", self.Tc) + rhoc = self._constants.get("rhoref", [self.rhoc])[0] + Tc = self._constants.get("Tref", [self.Tc])[0] delta = rho/rhoc tau = Tc/T ideal = self._phi0(tau, delta) @@ -1918,7 +1918,7 @@ def _virial(self, T): * B: ∂fir/∂δ|δ->0 * C: ∂²fir/∂δ²|δ->0 """ - Tc = self._constants.get("Tref", self.Tc) + Tc = self._constants.get("Tref", [self.Tc])[0] tau = Tc/T B = C = 0 delta = 1e-200 @@ -2030,9 +2030,9 @@ def _derivDimensional(self, rho, T): prop["firdd"] = 0 return prop - R = self._constants.get("R")/self._constants.get("M", self.M) - rhoc = self._constants.get("rhoref", self.rhoc) - Tc = self._constants.get("Tref", self.Tc) + R = self._constants.get("R")[0]/self._constants.get("M", self.M) + rhoc = self._constants.get("rhoref", [self.rhoc])[0] + Tc = self._constants.get("Tref", [self.Tc])[0] delta = rho/rhoc tau = Tc/T @@ -2365,7 +2365,7 @@ class IAPWS95(MEoS): 27.5075105]} _constants = { - "R": 8.314371357587, + "R": [8.314371357587], "nr1": [0.12533547935523e-1, 0.78957634722828e1, -0.87803203303561e1, 0.31802509345418, -0.26145533859358, -0.78199751687981e-2, @@ -2716,7 +2716,7 @@ class D2O(MEoS): "ao_hyp": [], "hyp": []} _constants = { - "R": 8.3144598, + "R": [8.3144598], "nr1": [0.122082060e-1, 0.296956870e1, -0.379004540e1, 0.941089600, -0.922466250, -0.139604190e-1], From 6478e8aca733762e60b64f4535611da20330fbc3 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sun, 14 Mar 2021 01:43:52 -0500 Subject: [PATCH 031/102] Significant mypy additions. This should be entirely type hints, and some explicitly conversions from integer to float by adding ".0". This commit has introduced nearly 200 mypy type errors, some of which are going to require more significant thought, so this seemed like a good place to commit even though it's a bit of a mess at the moment. --- iapws/_iapws.py | 61 ++++++------ iapws/_utils.py | 7 +- iapws/ammonia.py | 15 +-- iapws/humidAir.py | 46 ++++----- iapws/iapws08.py | 43 +++++---- iapws/iapws95.py | 98 +++++++++---------- iapws/iapws97.py | 238 +++++++++++++++++++++++----------------------- 7 files changed, 258 insertions(+), 250 deletions(-) diff --git a/iapws/_iapws.py b/iapws/_iapws.py index 3de7b37..b480385 100644 --- a/iapws/_iapws.py +++ b/iapws/_iapws.py @@ -31,6 +31,7 @@ from cmath import log as log_c from math import log, exp, tan, atan, acos, sin, pi, log10, copysign import warnings +from typing import Dict, Optional, Any from scipy.optimize import minimize @@ -59,7 +60,7 @@ # IAPWS-06 for Ice -def _Ice(T, P): +def _Ice(T: float, P: float) -> Dict[str, float]: """Basic state equation for Ice Ih Parameters @@ -150,14 +151,14 @@ def _Ice(T, P): t2 = complex(0.337315741065416, 0.335449415919309) r1 = complex(0.447050716285388e2, 0.656876847463481e2)*1e-3 - go = gop = gopp = 0 + go = gop = gopp = 0.0 for k in range(5): go += gok[k]*1e-3*(Pr-P0)**k for k in range(1, 5): gop += gok[k]*1e-3*k/Pt*(Pr-P0)**(k-1) for k in range(2, 5): gopp += gok[k]*1e-3*k*(k-1)/Pt**2*(Pr-P0)**(k-2) - r2 = r2p = 0 + r2 = r2p = 0.0 for k in range(3): r2 += r2k[k]*(Pr-P0)**k for k in range(1, 3): @@ -207,7 +208,7 @@ def _Ice(T, P): # IAPWS-08 for Liquid water at 0.1 MPa -def _Liquid(T, P=0.1): +def _Liquid(T: float, P: float = 0.1) -> Dict[str, float]: """Supplementary release on properties of liquid water at 0.1 MPa Parameters @@ -387,29 +388,29 @@ def _Liquid(T, P=0.1): class _Supercooled_minimize(object): - def __init__(self, L, omega, xmin, xmax): + def __init__(self, L: float, omega: float, xmin: float, xmax: float): self.L = L self.omega = omega self.xmin = xmin self.xmax = xmax self.f_inner_value_sign = 0.0 - def f(self, x): + def f(self, x: float) -> float: f_inner_value = self.L+log(x/(1-x))+self.omega*(1-2*x) self.f_inner_value_sign = copysign(1.0, f_inner_value) return abs(f_inner_value) - def jac(self, x): + def jac(self, x: float) -> float: return self.f_inner_value_sign*(1/(x*(1 - x)) - 2*self.omega) @property - def x(self): + def x(self) -> float: return minimize(self.f, x0=((self.xmin+self.xmax)/2,), bounds=((self.xmin, self.xmax),), jac=self.jac)["x"][0] # IAPWS-15 for supercooled liquid water -def _Supercooled(T, P): +def _Supercooled(T: float, P: float): """Guideline on thermodynamic properties of supercooled water Parameters @@ -493,16 +494,16 @@ def _Supercooled(T, P): 4.3773754, -2.9967770e-3, -9.6558018e-1, 3.7595286, 1.2632441, 2.8542697e-1, -8.5994947e-1, -3.2916153e-1, 9.0019616e-2, 8.1149726e-2, -3.2788213] - ai = [0, 0, 1, -0.2555, 1.5762, 1.6400, 3.6385, -0.3828, 1.6219, 4.3287, + ai = [0.0, 0.0, 1.0, -0.2555, 1.5762, 1.6400, 3.6385, -0.3828, 1.6219, 4.3287, 3.4763, 5.1556, -0.3593, 5.0361, 2.9786, 6.2373, 4.0460, 5.3558, 9.0157, 1.2194] - bi = [0, 1, 0, 2.1051, 1.1422, 0.9510, 0, 3.6402, 2.0760, -0.0016, 2.2769, + bi = [0.0, 1.0, 0.0, 2.1051, 1.1422, 0.9510, 0.0, 3.6402, 2.0760, -0.0016, 2.2769, 0.0008, 0.3706, -0.3975, 2.9730, -0.3180, 2.9805, 2.9265, 0.4456, 0.1298] - di = [0, 0, 0, -0.0016, 0.6894, 0.0130, 0.0002, 0.0435, 0.0500, 0.0004, + di = [0.0, 0.0, 0.0, -0.0016, 0.6894, 0.0130, 0.0002, 0.0435, 0.0500, 0.0004, 0.0528, 0.0147, 0.8584, 0.9924, 1.0041, 1.0961, 1.0228, 1.0303, 1.6180, 0.5213] - phir = phirt = phirp = phirtt = phirtp = phirpp = 0 + phir = phirt = phirp = phirtt = phirtp = phirpp = 0.0 for c, a, b, d in zip(ci, ai, bi, di): phir += c*tau_**a*p_**b*exp(-d*p_) phirt += c*a*tau_**(a-1)*p_**b*exp(-d*p_) @@ -580,7 +581,7 @@ def _Supercooled(T, P): return prop -def _Sublimation_Pressure(T): +def _Sublimation_Pressure(T: float) -> float: """Sublimation Pressure correlation Parameters @@ -621,7 +622,7 @@ def _Sublimation_Pressure(T): raise NotImplementedError("Incoming out of bound") -def _Melting_Pressure(T, ice="Ih"): +def _Melting_Pressure(T: float, ice: str = "Ih") -> float: """Melting Pressure correlation Parameters @@ -698,7 +699,8 @@ def _Melting_Pressure(T, ice="Ih"): # Transport properties -def _Viscosity(rho, T, fase=None, drho=None): +def _Viscosity(rho: float, T: float, fase: Optional[Any] = None, + drho: float = None) -> float: """Equation for the Viscosity Parameters @@ -787,7 +789,8 @@ def _Viscosity(rho, T, fase=None, drho=None): return mu*1e-6 -def _ThCond(rho, T, fase=None, drho=None): +def _ThCond(rho: float, T: float, fase: Optional[Any] = None, + drho: Optional[float] = None) -> float: """Equation for the thermal conductivity Parameters @@ -888,7 +891,7 @@ def _ThCond(rho, T, fase=None, drho=None): return 1e-3*k -def _Tension(T): +def _Tension(T: float) -> float: """Equation for the surface tension Parameters @@ -930,7 +933,7 @@ def _Tension(T): raise NotImplementedError("Incoming out of bound") -def _Dielectric(rho, T): +def _Dielectric(rho: float, T: float) -> float: """Equation for the Dielectric constant Parameters @@ -992,7 +995,7 @@ def _Dielectric(rho, T): return e -def _Refractive(rho, T, l=0.5893): +def _Refractive(rho: float, T: float, l: float = 0.5893) -> float: """Equation for the refractive index Parameters @@ -1046,7 +1049,7 @@ def _Refractive(rho, T, l=0.5893): return ((2*A+1)/(1-A))**0.5 -def _Kw(rho, T): +def _Kw(rho: float, T: float) -> float: """Equation for the ionization constant of ordinary water Parameters @@ -1099,7 +1102,7 @@ def _Kw(rho, T): return pKw -def _Conductivity(rho, T): +def _Conductivity(rho: float, T: float) -> float: """Equation for the electrolytic conductivity of liquid and dense supercrítical water @@ -1153,7 +1156,7 @@ def _Conductivity(rho, T): # Heavy water transport properties -def _D2O_Viscosity(rho, T): +def _D2O_Viscosity(rho: float, T: float) -> float: """Equation for the Viscosity of heavy water Parameters @@ -1202,7 +1205,7 @@ def _D2O_Viscosity(rho, T): return 55.2651e-6*fi0*fi1 -def _D2O_ThCond(rho, T): +def _D2O_ThCond(rho: float, T: float) -> float: """Equation for the thermal conductivity of heavy water Parameters @@ -1251,7 +1254,7 @@ def _D2O_ThCond(rho, T): return 0.742128e-3*(Lo+Lr+Lc+Ll) -def _D2O_Tension(T): +def _D2O_Tension(T: float) -> float: """Equation for the surface tension of heavy water Parameters @@ -1289,7 +1292,7 @@ def _D2O_Tension(T): raise NotImplementedError("Incoming out of bound") -def _D2O_Sublimation_Pressure(T): +def _D2O_Sublimation_Pressure(T: float) -> float: """Sublimation Pressure correlation for heavy water Parameters @@ -1330,7 +1333,7 @@ def _D2O_Sublimation_Pressure(T): raise NotImplementedError("Incoming out of bound") -def _D2O_Melting_Pressure(T, ice="Ih"): +def _D2O_Melting_Pressure(T: float, ice: str = "Ih") -> float: """Melting Pressure correlation for heavy water Parameters @@ -1391,7 +1394,7 @@ def _D2O_Melting_Pressure(T, ice="Ih"): return P -def _Henry(T, gas, liquid="H2O"): +def _Henry(T: float, gas: str, liquid: str = "H2O") -> float: """Equation for the calculation of Henry's constant Parameters @@ -1515,7 +1518,7 @@ def _Henry(T, gas, liquid="H2O"): return kh -def _Kvalue(T, gas, liquid="H2O"): +def _Kvalue(T: float, gas: str, liquid: str = "H2O") -> float: """Equation for the vapor-liquid distribution constant Parameters diff --git a/iapws/_utils.py b/iapws/_utils.py index 2731970..8b89404 100644 --- a/iapws/_utils.py +++ b/iapws/_utils.py @@ -12,9 +12,10 @@ """ from __future__ import division +from typing import Any -def getphase(Tc, Pc, T, P, x, region): +def getphase(Tc: float, Pc: float, T: float, P: float, x: float, region: int) -> str: """Return fluid phase string name Parameters @@ -117,7 +118,7 @@ class _fase(object): hInput = None -def deriv_H(state, z, x, y, fase): +def deriv_H(state: Any, z: str, x: str, y: str, fase) -> float: r"""Calculate generic partial derivative :math:`\left.\frac{\partial z}{\partial x}\right|_{y}` from a fundamental helmholtz free energy equation of state @@ -192,7 +193,7 @@ def deriv_H(state, z, x, y, fase): return mul*deriv -def deriv_G(state, z, x, y, fase): +def deriv_G(state: Any, z: str, x: str, y: str, fase) -> float: r"""Calculate generic partial derivative :math:`\left.\frac{\partial z}{\partial x}\right|_{y}` from a fundamental Gibbs free energy equation of state diff --git a/iapws/ammonia.py b/iapws/ammonia.py index f8673c0..5518548 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -13,6 +13,7 @@ from __future__ import division from math import exp, log, pi import warnings +from typing import Dict, Optional from scipy.constants import Boltzmann from .iapws95 import MEoS, IAPWS95, mainClassDoc @@ -86,7 +87,7 @@ class NH3(MEoS): "ao": [-.38435, -4.0846, -6.6634, -0.31881e2, 0.21306e3, -0.24648e3], "exp": [0.218, 0.55, 1.5, 3.7, 5.5, 5.8]} - def _visco(self, rho, T, fase=None): + def _visco(self, rho: float, T: float, fase=None) -> Optional[float]: """Equation for the Viscosity Parameters @@ -140,7 +141,7 @@ def _visco(self, rho, T, fase=None): mu = muo + mub + mur return mu*1e-6 - def _thermo(self, rho, T, fase): + def _thermo(self, rho: float, T: float, fase) -> Optional[float]: """Equation for the thermal conductivity Parameters @@ -209,7 +210,7 @@ class H2ONH3(object): # TODO: Add equilibrium routine - def _prop(self, rho, T, x): + def _prop(self, rho: float, T: float, x: float) -> Dict[str, float]: """Thermodynamic properties of ammonia-water mixtures Parameters @@ -287,7 +288,7 @@ def _prop(self, rho, T, x): prop["fugNH3"] = Z*exp(fir+delta*fird+(1-x)*F) return prop - def _phi0(self, rho, T, x): + def _phi0(self, rho: float, T: float, x: float) -> Dict[str, float]: """Ideal gas Helmholtz energy of binary mixtures and derivatives Parameters @@ -381,7 +382,7 @@ def _phi0(self, rho, T, x): prop["fiodt"] = fiodt return prop - def _phir(self, rho, T, x): + def _phir(self, rho: float, T: float, x: float) -> Dict[str, float]: """Residual contribution to the free Helmholtz energy Parameters @@ -457,7 +458,7 @@ def _phir(self, rho, T, x): tau/Tn*dTnx*prop["firt"] return prop - def _Dphir(self, tau, delta, x): + def _Dphir(self, tau: float, delta: float, x: float) -> Dict[str, float]: """Departure function to the residual contribution to the free Helmholtz energy @@ -564,7 +565,7 @@ def _Dphir(self, tau, delta, x): return prop -def Ttr(x): +def Ttr(x: float) -> float: """Equation for the triple point of ammonia-water mixture Parameters diff --git a/iapws/humidAir.py b/iapws/humidAir.py index 23c8b9b..987aea3 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -16,7 +16,7 @@ from __future__ import division from math import exp, log, pi, atan import warnings -from typing import Tuple +from typing import Tuple, Dict, Any from scipy.optimize import fsolve @@ -30,7 +30,7 @@ R = 8.314472 # J/molK -def _virial(T): +def _virial(T: float) -> Dict[str, float]: """Virial equations for humid air Parameters @@ -162,7 +162,7 @@ def _virial(T): return prop -def _fugacity(T, P, x): +def _fugacity(T: float, P: float, x: float) -> float: """Fugacity equation for humid air Parameters @@ -228,8 +228,10 @@ class MEoSBlend(MEoS): ancillary dew and bubble point """ + _blend: Dict[str, Any] + @classmethod - def _dewP(cls, T): + def _dewP(cls, T: float) -> float: """Using ancillary equation return the pressure of dew point""" c = cls._blend["dew"] Tj = cls._blend["Tj"] @@ -243,7 +245,7 @@ def _dewP(cls, T): return P @classmethod - def _bubbleP(cls, T): + def _bubbleP(cls, T: float) -> float: """Using ancillary equation return the pressure of bubble point""" c = cls._blend["bubble"] Tj = cls._blend["Tj"] @@ -336,7 +338,7 @@ class Air(MEoSBlend): "exp": [0.5, 1, 2.5, 4]} @classmethod - def _Liquid_Density(cls, T): + def _Liquid_Density(cls, T: float) -> float: """Auxiliary equation for the density or saturated liquid Parameters @@ -362,7 +364,7 @@ def _Liquid_Density(cls, T): return rho @staticmethod - def _visco(rho, T, fase=None): + def _visco(rho: float, T: float, fase=None) -> float: """Equation for the Viscosity Parameters @@ -392,7 +394,7 @@ def _visco(rho, T, fase=None): b = [0.431, -0.4623, 0.08406, 0.005341, -0.00331] T_ = log(T/ek) - suma = 0 + suma = 0.0 for i, bi in enumerate(b): suma += bi*T_**i omega = exp(suma) @@ -407,7 +409,7 @@ def _visco(rho, T, fase=None): g_poly = [0, 0, 0, 1, 1] # Eq 3 - mur = 0 + mur = 0.0 for n, t, d, l, g in zip(n_poly, t_poly, d_poly, l_poly, g_poly): mur += n*tau**t*delta**d*exp(-g*delta**l) @@ -415,7 +417,7 @@ def _visco(rho, T, fase=None): mu = muo+mur return mu*1e-6 - def _thermo(self, rho, T, fase=None): + def _thermo(self, rho: float, T: float, fase=None) -> float: """Equation for the thermal conductivity Parameters @@ -447,7 +449,7 @@ def _thermo(self, rho, T, fase=None): b = [0.431, -0.4623, 0.08406, 0.005341, -0.00331] T_ = log(T/ek) - suma = 0 + suma = 0.0 for i, bi in enumerate(b): suma += bi*T_**i omega = exp(suma) @@ -467,11 +469,11 @@ def _thermo(self, rho, T, fase=None): l_poly = [0, 0, 2, 2, 2, 2] # Eq 6 - lr = 0 + lr = 0.0 for n, t, d, l, g in zip(n_poly, t_poly, d_poly, l_poly, g_poly): lr += n*tau**t*delta**d*exp(-g*delta**l) - lc = 0 + lc = 0.0 # FIXME: Tiny desviation in the test in paper, 0.06% at critical point if fase: qd = 0.31 @@ -504,7 +506,7 @@ def _thermo(self, rho, T, fase=None): # Eq 7 lc = rho*fase.cp*k*1.01*T/6/pi/Xi/fase.mu*(Omega-Omega0)*1e15 else: - lc = 0 + lc = 0.0 # Eq 4 k = lo+lr+lc @@ -609,7 +611,7 @@ def __call__(self, **kwargs): self.msg = "" @property - def calculable(self): + def calculable(self) -> bool: """Check if inputs are enough to define state""" self._mode = "" if self.kwargs["T"] and self.kwargs["P"]: @@ -628,7 +630,7 @@ def calculable(self): return bool(self._mode) and bool(self._composition) - def calculo(self): + def calculo(self) -> None: """Calculate procedure""" T = self.kwargs["T"] rho = self.kwargs["rho"] @@ -690,14 +692,14 @@ def t_func(T: float) -> float: self.xa_sat = A_sat*MW/Ma/(1-A_sat*(1-MW/Ma)) self.RH = (1-self.xa)/(1-self.xa_sat) - def derivative(self, z, x, y): + def derivative(self, z: str, x: str, y: str): """ Wrapper derivative for custom derived properties where x, y, z can be: P, T, v, rho, u, h, s, g, a """ return deriv_G(self, z, x, y, self) - def _eq(self, T, P): + def _eq(self, T: float, P: float) -> float: """Procedure for calculate the composition in saturation state Parameters @@ -731,7 +733,7 @@ def f(parr: Tuple[float, float]) -> Tuple[float, float]: Asat = rinput[0][1] return Asat - def _prop(self, T, rho, fav): + def _prop(self, T: float, rho: float, fav: Dict[str, float]) -> Dict[str, float]: """Thermodynamic properties of humid air Parameters @@ -783,7 +785,7 @@ def _prop(self, T, rho, fav): / fav["firtt"]+2*rho*fav["fird"]*1000)**0.5 # Eq T10 return prop - def _coligative(self, rho, A, fav): + def _coligative(self, rho: float, A: float, fav: Dict[str, float]) -> Dict[str, float]: """Miscelaneous properties of humid air Parameters @@ -823,7 +825,7 @@ def _coligative(self, rho, A, fav): prop["xw"] = 1-prop["xa"] return prop - def _fav(self, T, rho, A): + def _fav(self, T: float, rho: float, A: float) -> Dict[str, float]: r"""Specific Helmholtz energy of humid air and derivatives Parameters @@ -895,7 +897,7 @@ def _fav(self, T, rho, A): prop["firdd"] = (1-A)**3*fv["firdd"]+A**3*fa["firdd"]+fmix["firdd"] return prop - def _fmix(self, T, rho, A): + def _fmix(self, T: float, rho: float, A: float) -> Dict[str, float]: r"""Specific Helmholtz energy of air-water interaction Parameters diff --git a/iapws/iapws08.py b/iapws/iapws08.py index a401426..398c4cf 100644 --- a/iapws/iapws08.py +++ b/iapws/iapws08.py @@ -21,6 +21,7 @@ from __future__ import division from math import exp, log import warnings +from typing import Dict, Tuple from scipy.optimize import fsolve @@ -252,7 +253,7 @@ def calculo(self): self.osm = None self.haline = None - def derivative(self, z, x, y): + def derivative(self, z: str, x: str, y: str): """ Wrapper derivative for custom derived properties where x, y, z can be: P, T, v, u, h, s, g, a @@ -260,7 +261,7 @@ def derivative(self, z, x, y): return deriv_G(self, z, x, y, self) @classmethod - def _water(cls, T, P): + def _water(cls, T: float, P: float) -> Dict[str, float]: """Get properties of pure water, Table4 pag 8""" water = IAPWS95(P=P, T=T) prop = {} @@ -276,7 +277,7 @@ def _water(cls, T, P): return prop @classmethod - def _waterIF97(cls, T, P): + def _waterIF97(cls, T: float, P: float) -> Dict[str, float]: water = IAPWS97(P=P, T=T) betas = water.derivative("T", "P", "s", water) prop = {} @@ -291,7 +292,7 @@ def _waterIF97(cls, T, P): return prop @classmethod - def _waterSupp(cls, T, P): + def _waterSupp(cls, T: float, P: float) -> Dict[str, float]: """ Get properties of pure water using the supplementary release SR7-09, Table4 pag 6 @@ -318,7 +319,7 @@ def _waterSupp(cls, T, P): 0.635113936641785e2, -0.222897317140459e2, 0.817060541818112e1, 0.305081646487967e1, -0.963108119393062e1] - g, gt, gp, gtt, gtp, gpp = 0, 0, 0, 0, 0, 0 + g = gt = gp = gtt = gtp = gpp = 0.0 for j, k, gi in zip(J, K, G): g += gi*tau**j*pi**k if j >= 1: @@ -339,12 +340,12 @@ def _waterSupp(cls, T, P): prop["gtt"] = gtt/40**2*1e-3 prop["gtp"] = gtp/40/100*1e-6 prop["gpp"] = gpp/100**2*1e-6 - prop["gs"] = 0 - prop["gsp"] = 0 + prop["gs"] = 0.0 + prop["gsp"] = 0.0 return prop @classmethod - def _saline(cls, T, P, S): + def _saline(cls, T: float, P: float, S: float) -> Dict[str, float]: """Eq 4""" # Check input in range of validity if T <= 261 or T > 353 or P <= 0 or P > 100 or S < 0 or S > 0.12: @@ -387,7 +388,7 @@ def _saline(cls, T, P, S): -0.111282734326413e2, -0.262480156590992e1, 0.704658803315449e1, -0.792001547211682e1] - g, gt, gp, gtt, gtp, gpp, gs, gsp = 0, 0, 0, 0, 0, 0, 0, 0 + g = gt = gp = gtt = gtp = gpp = gs = gsp = 0.0 # Calculate only for some salinity if S != 0: @@ -425,7 +426,7 @@ def _saline(cls, T, P, S): return prop -def _Tb(P, S): +def _Tb(P: float, S: float) -> float: """Procedure to calculate the boiling temperature of seawater Parameters @@ -445,7 +446,7 @@ def _Tb(P, S): IAPWS, Advisory Note No. 5: Industrial Calculation of the Thermodynamic Properties of Seawater, http://www.iapws.org/relguide/Advise5.html, Eq 7 """ - def f(T): + def f(T: float) -> float: pw = _Region1(T, P) gw = pw["h"]-T*pw["s"] @@ -459,7 +460,7 @@ def f(T): return Tb -def _Tf(P, S): +def _Tf(P: float, S: float) -> float: """Procedure to calculate the freezing temperature of seawater Parameters @@ -479,7 +480,7 @@ def _Tf(P, S): IAPWS, Advisory Note No. 5: Industrial Calculation of the Thermodynamic Properties of Seawater, http://www.iapws.org/relguide/Advise5.html, Eq 12 """ - def f(T): + def f(T: float) -> float: T = float(T) pw = _Region1(T, P) gw = pw["h"]-T*pw["s"] @@ -493,7 +494,7 @@ def f(T): return Tf -def _Triple(S): +def _Triple(S: float) -> Dict[str, float]: """Procedure to calculate the triple point pressure and temperature for seawater @@ -515,7 +516,7 @@ def _Triple(S): IAPWS, Advisory Note No. 5: Industrial Calculation of the Thermodynamic Properties of Seawater, http://www.iapws.org/relguide/Advise5.html, Eq 7 """ - def f(parr): + def f(parr: Tuple[float, float]) -> Tuple[float, float]: T, P = parr pw = _Region1(T, P) gw = pw["h"]-T*pw["s"] @@ -536,7 +537,7 @@ def f(parr): return prop -def _OsmoticPressure(T, P, S): +def _OsmoticPressure(T: float, P: float, S: float) -> float: """Procedure to calculate the osmotic pressure of seawater Parameters @@ -561,7 +562,7 @@ def _OsmoticPressure(T, P, S): pw = _Region1(T, P) gw = pw["h"]-T*pw["s"] - def f(Posm): + def f(Posm: float) -> float: pw2 = _Region1(T, P+Posm) gw2 = pw2["h"]-T*pw2["s"] ps = SeaWater._saline(T, P+Posm, S) @@ -571,7 +572,7 @@ def f(Posm): return Posm -def _ThCond_SeaWater(T, P, S): +def _ThCond_SeaWater(T: float, P: float, S: float) -> float: """Equation for the thermal conductivity of seawater Parameters @@ -626,7 +627,7 @@ def _ThCond_SeaWater(T, P, S): return DL -def _Tension_SeaWater(T, S): +def _Tension_SeaWater(T: float, S: float) -> float: """Equation for the surface tension of seawater Parameters @@ -673,7 +674,7 @@ def _Tension_SeaWater(T, S): return sigma -def _solNa2SO4(T, mH2SO4, mNaCl): +def _solNa2SO4(T: float, mH2SO4: float, mNaCl: float) -> float: """Equation for the solubility of sodium sulfate in aqueous mixtures of sodium chloride and sulfuric acid @@ -730,7 +731,7 @@ def _solNa2SO4(T, mH2SO4, mNaCl): return S -def _critNaCl(x): +def _critNaCl(x: float) -> Dict[str, float]: """Equation for the critical locus of aqueous solutions of sodium chloride Parameters diff --git a/iapws/iapws95.py b/iapws/iapws95.py index bd2ddae..4c5ff33 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -97,7 +97,7 @@ def _phir(tau: float, delta: float, coef: Dict[str, List[float]]) -> float: return fir -def _phird(tau, delta, coef): +def _phird(tau: float, delta: float, coef: Dict[str, List[float]]) -> float: r"""Residual contribution to the adimensional free Helmholtz energy, delta derivative @@ -123,7 +123,7 @@ def _phird(tau, delta, coef): Scientific Use, September 2016, Table 5 http://www.iapws.org/relguide/IAPWS-95.html """ - fird = 0 + fird = 0.0 # Polinomial terms nr1 = coef.get("nr1", []) @@ -177,7 +177,7 @@ def _phird(tau, delta, coef): return fird -def _phirt(tau, delta, coef): +def _phirt(tau: float, delta: float, coef: Dict[str, List[float]]) -> float: r"""Residual contribution to the adimensional free Helmholtz energy, tau derivative @@ -203,7 +203,7 @@ def _phirt(tau, delta, coef): Scientific Use, September 2016, Table 5 http://www.iapws.org/relguide/IAPWS-95.html """ - firt = 0 + firt = 0.0 # Polinomial terms nr1 = coef.get("nr1", []) @@ -440,7 +440,7 @@ def __call__(self, **kwargs): "extension") @property - def calculable(self): + def calculable(self) -> bool: """Check if inputs are enough to define state""" self._mode = "" if self.kwargs["T"] and self.kwargs["P"]: @@ -1566,14 +1566,14 @@ def fill(self, fase, estado): fase.epsilon = None fase.n = None - def derivative(self, z, x, y, fase): + def derivative(self, z: str, x: str, y: str, fase: _fase): """ Wrapper derivative for custom derived properties where x, y, z can be: P, T, v, rho, u, h, s, g, a """ return deriv_H(self, z, x, y, fase) - def _saturation(self, T): + def _saturation(self, T: float) -> Tuple[float, float, float]: """Saturation calculation for two phase search""" rhoc = self._constants.get("rhoref", [self.rhoc])[0] Tc = self._constants.get("Tref", [self.Tc])[0] @@ -1611,7 +1611,7 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: Ps = self.R*T*rhoL*rhoG/(rhoL-rhoG)*(firL-firG+log(deltaL/deltaG)) return rhoL, rhoG, Ps - def _Helmholtz(self, rho, T): + def _Helmholtz(self, rho: float, T: float) -> Dict[str, float]: """Calculated properties from helmholtz free energy and derivatives Parameters @@ -1684,7 +1684,7 @@ def _Helmholtz(self, rho, T): 1+(delta*fird+delta**2*firdd)/(1+delta*fird)) return propiedades - def _prop0(self, rho, T): + def _prop0(self, rho: float, T: float) -> _fase: """Ideal gas properties""" rhoc = self._constants.get("rhoref", [self.rhoc])[0] Tc = self._constants.get("Tref", [self.Tc])[0] @@ -1700,11 +1700,11 @@ def _prop0(self, rho, T): propiedades.s = self.R*(tau*fiot-fio) propiedades.cv = -self.R*tau**2*fiott propiedades.cp = self.R*(-tau**2*fiott+1) - propiedades.alfap = 1/T + propiedades.alfap = 1.0/T propiedades.betap = rho return propiedades - def _phi0(self, tau, delta): + def _phi0(self, tau: float, delta: float) -> Dict[str, float]: """Ideal gas Helmholtz free energy and derivatives Parameters @@ -1769,7 +1769,7 @@ def _phi0(self, tau, delta): prop["fiodt"] = fiodt return prop - def _phir(self, tau, delta): + def _phir(self, tau: float, delta: float) -> Dict[str, float]: """Residual contribution to the free Helmholtz energy Parameters @@ -1797,7 +1797,7 @@ def _phir(self, tau, delta): Scientific Use, September 2016, Table 5 http://www.iapws.org/relguide/IAPWS-95.html """ - fir = fird = firdd = firt = firtt = firdt = 0 + fir = fird = firdd = firt = firtt = firdt = 0.0 # Polinomial terms nr1 = self._constants.get("nr1", []) @@ -1903,7 +1903,7 @@ def _phir(self, tau, delta): prop["firdt"] = firdt return prop - def _virial(self, T): + def _virial(self, T: float) -> Dict[str, float]: """Virial coefficient Parameters @@ -1920,7 +1920,7 @@ def _virial(self, T): """ Tc = self._constants.get("Tref", [self.Tc])[0] tau = Tc/T - B = C = 0 + B = C = 0.0 delta = 1e-200 # Polinomial terms @@ -1991,7 +1991,7 @@ def _virial(self, T): prop["C"] = C return prop - def _derivDimensional(self, rho, T): + def _derivDimensional(self, rho: float, T: float) -> Dict[str, float]: """Calcule the dimensional form or Helmholtz free energy derivatives Parameters @@ -2022,12 +2022,12 @@ def _derivDimensional(self, rho, T): """ if not rho: prop = {} - prop["fir"] = 0 - prop["firt"] = 0 - prop["fird"] = 0 - prop["firtt"] = 0 - prop["firdt"] = 0 - prop["firdd"] = 0 + prop["fir"] = 0.0 + prop["firt"] = 0.0 + prop["fird"] = 0.0 + prop["firtt"] = 0.0 + prop["firdt"] = 0.0 + prop["firdd"] = 0.0 return prop R = self._constants.get("R")[0]/self._constants.get("M", self.M) @@ -2060,7 +2060,7 @@ def _derivDimensional(self, rho, T): prop["firdd"] = R*T/rhoc**2*(fiodd+firdd) return prop - def _surface(self, T): + def _surface(self, T: float) -> float: """Generic equation for the surface tension Parameters @@ -2086,7 +2086,7 @@ def _surface(self, T): return sigma @classmethod - def _Vapor_Pressure(cls, T): + def _Vapor_Pressure(cls, T: float) -> float: """Auxiliary equation for the vapour pressure Parameters @@ -2114,7 +2114,7 @@ def _Vapor_Pressure(cls, T): return Pv @classmethod - def _Liquid_Density(cls, T): + def _Liquid_Density(cls, T: float) -> float: """Auxiliary equation for the density of saturated liquid Parameters @@ -2145,7 +2145,7 @@ def _Liquid_Density(cls, T): return rho @classmethod - def _Vapor_Density(cls, T): + def _Vapor_Density(cls, T: float) -> float: """Auxiliary equation for the density of saturated vapor Parameters @@ -2176,7 +2176,7 @@ def _Vapor_Density(cls, T): return rho @classmethod - def _dPdT_sat(cls, T): + def _dPdT_sat(cls, T: float) -> float: """Auxiliary equation for the dP/dT along saturation line Parameters @@ -2213,7 +2213,7 @@ def mainClassDoc(): """ def decorator(f): # __doc__ is only writable in python3. - # The doc build must be done with python3 so this snnippet do the work + # The doc build must be done with python3 so this snippet do the work py_version = platform.python_version() if py_version[0] == "3": doc = f.__doc__.split(os.linesep) @@ -2431,7 +2431,7 @@ class IAPWS95(MEoS): -63.9201063], "exp": [1, 2, 4, 9, 18.5, 35.5]} - def _phi0(self, tau, delta): + def _phi0(self, tau: float, delta: float) -> Dict[str, float]: """Low temperature extension of the IAPWS-95""" prop = MEoS._phi0(self, tau, delta) @@ -2443,7 +2443,7 @@ def _phi0(self, tau, delta): prop["fiott"] += fextt return prop - def _phiex(self, T): + def _phiex(self, T: float) -> Tuple[float, float, float]: """Low temperature extension""" tau = self.Tc/T E = 0.278296458178592 @@ -2455,7 +2455,7 @@ def _phiex(self, T): return fex, fext, fextt @classmethod - def _alfa_sat(cls, T): + def _alfa_sat(cls, T: float) -> float: """Auxiliary equation for the alfa coefficient for calculate the enthalpy along the saturation line @@ -2479,13 +2479,13 @@ def _alfa_sat(cls, T): -135.003439, 0.981825814] expi = [0, -19, 1, 4.5, 5, 54.5] Tita = T/cls.Tc - alfa = 0 + alfa = 0.0 for d, x in zip(di, expi): alfa += d*Tita**x return alfa @classmethod - def _phi_sat(cls, T): + def _phi_sat(cls, T: float) -> float: """Auxiliary equation for the phi coefficient for calculate the entropy along the saturation line @@ -2509,7 +2509,7 @@ def _phi_sat(cls, T): -135.003439*5/4, 0.981825814*109/107] expi = [0, -20, None, 3.5, 4, 53.5] Tita = T/cls.Tc - suma = 0 + suma = 0.0 for d, x in zip(di, expi): if x is None: suma += d*log(Tita) @@ -2519,7 +2519,7 @@ def _phi_sat(cls, T): return phi @classmethod - def _Liquid_Enthalpy(cls, T): + def _Liquid_Enthalpy(cls, T: float) -> float: """Auxiliary equation for the specific enthalpy for saturated liquid Parameters @@ -2545,7 +2545,7 @@ def _Liquid_Enthalpy(cls, T): return h @classmethod - def _Vapor_Enthalpy(cls, T): + def _Vapor_Enthalpy(cls, T: float) -> float: """Auxiliary equation for the specific enthalpy for saturated vapor Parameters @@ -2571,7 +2571,7 @@ def _Vapor_Enthalpy(cls, T): return h @classmethod - def _Liquid_Entropy(cls, T): + def _Liquid_Entropy(cls, T: float) -> float: """Auxiliary equation for the specific entropy for saturated liquid Parameters @@ -2597,7 +2597,7 @@ def _Liquid_Entropy(cls, T): return s @classmethod - def _Vapor_Entropy(cls, T): + def _Vapor_Entropy(cls, T: float) -> float: """Auxiliary equation for the specific entropy for saturated vapor Parameters @@ -2622,21 +2622,21 @@ def _Vapor_Entropy(cls, T): s = phi+dpdT/rho*1000 return s - def _visco(self, rho, T, fase): + def _visco(self, rho: float, T: float, fase: Optional[Dict[str, float]]) -> float: ref = IAPWS95() st = ref._Helmholtz(rho, 1.5*Tc) delta = rho/rhoc drho = 1e3/self.R/1.5/Tc/(1+2*delta*st["fird"]+delta**2*st["firdd"]) return _Viscosity(rho, T, fase, drho) - def _thermo(self, rho, T, fase): + def _thermo(self, rho: float, T: float, fase: Optional[Dict[str, float]]) -> float: ref = IAPWS95() st = ref._Helmholtz(rho, 1.5*Tc) delta = rho/rhoc drho = 1e3/self.R/1.5/Tc/(1+2*delta*st["fird"]+delta**2*st["firdd"]) return _ThCond(rho, T, fase, drho) - def _surface(self, T): + def _surface(self, T: float) -> float: s = _Tension(T) return s @@ -2644,35 +2644,35 @@ def _surface(self, T): class IAPWS95_PT(IAPWS95): """Derivated class for direct P and T input""" - def __init__(self, P, T): + def __init__(self, P: float, T: float): IAPWS95.__init__(self, T=T, P=P) class IAPWS95_Ph(IAPWS95): """Derivated class for direct P and h input""" - def __init__(self, P, h): + def __init__(self, P: float, h: float): IAPWS95.__init__(self, P=P, h=h) class IAPWS95_Ps(IAPWS95): """Derivated class for direct P and s input""" - def __init__(self, P, s): + def __init__(self, P: float, s: float): IAPWS95.__init__(self, P=P, s=s) class IAPWS95_Px(IAPWS95): """Derivated class for direct P and v input""" - def __init__(self, P, x): + def __init__(self, P: float, x): IAPWS95.__init__(self, P=P, x=x) class IAPWS95_Tx(IAPWS95): """Derivated class for direct T and x input""" - def __init__(self, T, x): + def __init__(self, T: float, x): IAPWS95.__init__(self, T=T, x=x) @@ -2758,12 +2758,12 @@ class D2O(MEoS): -0.70412e2], "exp": [0.409, 1.766, 2.24, 3.04, 3.42, 6.9]} - def _visco(self, rho, T, fase): + def _visco(self, rho: float, T: float, fase) -> float: return _D2O_Viscosity(rho, T) - def _thermo(self, rho, T, fase): + def _thermo(self, rho: float, T: float, fase) -> float: return _D2O_ThCond(rho, T) - def _surface(self, T): + def _surface(self, T: float) -> float: s = _D2O_Tension(T) return s diff --git a/iapws/iapws97.py b/iapws/iapws97.py index 119c327..a80a2a1 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -84,7 +84,7 @@ from __future__ import division from math import sqrt, log, exp -from typing import Tuple, List +from typing import Tuple, Dict, List, Optional from scipy.optimize import fsolve, newton @@ -104,7 +104,7 @@ # Boundary Region1-Region3 -def _h13_s(s): +def _h13_s(s: float) -> float: """Define the boundary between Region 1 and 3, h=f(s) Parameters @@ -148,14 +148,14 @@ def _h13_s(s): n = [0.913965547600543, -0.430944856041991e-4, 0.603235694765419e2, 0.117518273082168e-17, 0.220000904781292, -0.690815545851641e2] - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (sigma-0.884)**i * (sigma-0.864)**j return 1700 * suma # Boundary Region2-Region3 -def _P23_T(T): +def _P23_T(T: float) -> float: """Define the boundary between Region 2 and 3, P=f(T) Parameters @@ -183,7 +183,7 @@ def _P23_T(T): return n[0]+n[1]*T+n[2]*T**2 -def _t_P(P): +def _t_P(P: float) -> float: """Define the boundary between Region 2 and 3, T=f(P) Parameters @@ -211,7 +211,7 @@ def _t_P(P): return n[1]+((P-n[2])/n[0])**0.5 -def _t_hs(h, s): +def _t_hs(h: float, s: float) -> float: """Define the boundary between Region 2 and 3, T=f(h,s) Parameters @@ -269,14 +269,14 @@ def _t_hs(h, s): 0.261907376402688e-5, -0.291626417025961e5, 0.140660774926165e-4, 0.783237062349385e7] - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (nu-0.727)**i * (sigma-0.864)**j return 900*suma # Saturated line -def _PSat_T(T): +def _PSat_T(T: float) -> float: """Define the saturated line, P=f(T) Parameters @@ -321,7 +321,7 @@ def _PSat_T(T): return (2*C/(-B+(B**2-4*A*C)**0.5))**4 -def _TSat_P(P): +def _TSat_P(P: float) -> float: """Define the saturated line, T=f(P) Parameters @@ -367,7 +367,7 @@ def _TSat_P(P): return (n[10]+D-((n[10]+D)**2-4*(n[9]+n[10]*D))**0.5)/2 -def _PSat_h(h): +def _PSat_h(h: float) -> float: """Define the saturated line, P=f(h) for region 3 Parameters @@ -415,13 +415,13 @@ def _PSat_h(h): -0.333775713645296e23, 0.356499469636328e11, -0.148547544720641e27, 0.330611514838798e19, 0.813641294467829e38] - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (nu-1.02)**i * (nu-0.608)**j return 22*suma -def _PSat_s(s): +def _PSat_s(s: float) -> float: """Define the saturated line, P=f(s) for region 3 Parameters @@ -468,13 +468,13 @@ def _PSat_s(s): -0.955586736431328e35, 0.187269814676188e24, 0.119254746466473e12, 0.110649277244882e37] - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (sigma-1.03)**i * (sigma-0.699)**j return 22*suma -def _h1_s(s): +def _h1_s(s: float) -> float: """Define the saturated line boundary between Region 1 and 4, h=f(s) Parameters @@ -527,13 +527,13 @@ def _h1_s(s): 0.573953875852936e7, 0.173226193407919e3, -0.363968822121321e-1, 0.834596332878346e-6, 0.503611916682674e1, 0.655444787064505e2] - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (sigma-1.09)**i * (sigma+0.366e-4)**j return 1700*suma -def _h3a_s(s): +def _h3a_s(s: float) -> float: """Define the saturated line boundary between Region 4 and 3a, h=f(s) Parameters @@ -582,13 +582,13 @@ def _h3a_s(s): -0.317714386511207e5, -0.945890406632871e5, -0.139273847088690e-5, 0.631052532240980] - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (sigma-1.09)**i * (sigma+0.366e-4)**j return 1700*suma -def _h2ab_s(s): +def _h2ab_s(s: float) -> float: """Define the saturated line boundary between Region 4 and 2a-2b, h=f(s) Parameters @@ -643,13 +643,13 @@ def _h2ab_s(s): 0.297478906557467e35, -0.953588761745473e20, 0.166957699620939e25, -0.175407764869978e33, 0.347581490626396e35, -0.710971318427851e39] - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (1/sigma1-0.513)**i * (sigma2-0.524)**j return 2800*exp(suma) -def _h2c3b_s(s): +def _h2c3b_s(s: float) -> float: """Define the saturated line boundary between Region 4 and 2c-3b, h=f(s) Parameters @@ -697,14 +697,14 @@ def _h2c3b_s(s): 0.396611982166538e12, -0.414716268484468e41, 0.359080103867382e19, -0.116994334851995e41] - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (sigma-1.02)**i * (sigma-0.726)**j return 2800*suma**4 # Region 1 -def _Region1(T, P): +def _Region1(T: float, P: float) -> Dict[str, float]: """Basic equation for region 1 Parameters @@ -776,7 +776,7 @@ def _Region1(T, P): -0.93537087292458e-25] Tr = 1386/T Pr = P/16.53 - g = gp = gpp = gt = gtt = gpt = 0 + g = gp = gpp = gt = gtt = gpt = 0.0 for i, j, ni in zip(I, J, n): g += ni * (7.1-Pr)**i * (Tr-1.222)**j gp -= ni*i * (7.1-Pr)**(i-1) * (Tr-1.222)**j @@ -801,7 +801,7 @@ def _Region1(T, P): return propiedades -def _Backward1_T_Ph(P, h): +def _Backward1_T_Ph(P: float, h: float) -> float: """ Backward equation for region 1, T=f(P,h) @@ -842,13 +842,13 @@ def _Backward1_T_Ph(P, h): Pr = P/1 nu = h/2500 - T = 0 + T = 0.0 for i, j, ni in zip(I, J, n): T += ni * Pr**i * (nu+1)**j return T -def _Backward1_T_Ps(P, s): +def _Backward1_T_Ps(P: float, s: float) -> float: """Backward equation for region 1, T=f(P,s) Parameters @@ -888,13 +888,13 @@ def _Backward1_T_Ps(P, s): Pr = P/1 sigma = s/1 - T = 0 + T = 0.0 for i, j, ni in zip(I, J, n): T += ni * Pr**i * (sigma+2)**j return T -def _Backward1_P_hs(h, s): +def _Backward1_P_hs(h: float, s: float) -> float: """Backward equation for region 1, P=f(h,s) Parameters @@ -937,14 +937,14 @@ def _Backward1_P_hs(h, s): nu = h/3400 sigma = s/7.6 - P = 0 + P = 0.0 for i, j, ni in zip(I, J, n): P += ni * (nu+0.05)**i * (sigma+0.05)**j return 100*P # Region 2 -def _Region2(T, P): +def _Region2(T: float, P: float) -> Dict[str, float]: """Basic equation for region 2 Parameters @@ -1027,7 +1027,7 @@ def _Region2(T, P): -1.2768608934681e-15, 7.3087610595061e-29, 5.5414715350778001e-17, -9.4369707241209998e-07] - gr = grp = grpp = grt = grtt = grpt = 0 + gr = grp = grpp = grt = grtt = grpt = 0.0 for i, j, ni in zip(Ir, Jr, nr): gr += ni * Pr**i * (Tr-0.5)**j grp += ni*i * Pr**(i-1) * (Tr-0.5)**j @@ -1054,7 +1054,7 @@ def _Region2(T, P): return propiedades -def Region2_cp0(Tr, Pr): +def Region2_cp0(Tr: float, Pr: float) -> Tuple[float, float, float, float, float, float]: """Ideal properties for Region 2 Parameters @@ -1090,7 +1090,7 @@ def Region2_cp0(Tr, Pr): go = log(Pr) gop = Pr**-1 gopp = -Pr**-2 - got = gott = gopt = 0 + got = gott = gopt = 0.0 for j, ni in zip(Jo, no): go += ni * Tr**j got += ni*j * Tr**(j-1) @@ -1098,7 +1098,7 @@ def Region2_cp0(Tr, Pr): return go, gop, gopp, got, gott, gopt -def _P_2bc(h): +def _P_2bc(h: float) -> float: """Define the boundary between Region 2b and 2c, P=f(h) Parameters @@ -1125,7 +1125,7 @@ def _P_2bc(h): return 905.84278514723-0.67955786399241*h+1.2809002730136e-4*h**2 -def _hbc_P(P): +def _hbc_P(P: float) -> float: """Define the boundary between Region 2b and 2c, h=f(P) Parameters @@ -1152,7 +1152,7 @@ def _hbc_P(P): return 0.26526571908428e4+((P-0.45257578905948e1)/1.2809002730136e-4)**0.5 -def _hab_s(s): +def _hab_s(s: float) -> float: """Define the boundary between Region 2a and 2b, h=f(s) Parameters @@ -1180,16 +1180,16 @@ def _hab_s(s): smin = _Region2(_TSat_P(4), 4)["s"] smax = _Region2(1073.15, 4)["s"] if s < smin: - h = 0 + h = 0.0 elif s > smax: - h = 5000 + h = 5000.0 else: h = -0.349898083432139e4 + 0.257560716905876e4*s - \ 0.421073558227969e3*s**2+0.276349063799944e2*s**3 return h -def _Backward2a_T_Ph(P, h): +def _Backward2a_T_Ph(P: float, h: float) -> float: """Backward equation for region 2a, T=f(P,h) Parameters @@ -1236,13 +1236,13 @@ def _Backward2a_T_Ph(P, h): Pr = P/1 nu = h/2000 - T = 0 + T = 0.0 for i, j, ni in zip(I, J, n): T += ni * Pr**i * (nu-2.1)**j return T -def _Backward2b_T_Ph(P, h): +def _Backward2b_T_Ph(P: float, h: float) -> float: """Backward equation for region 2b, T=f(P,h) Parameters @@ -1290,13 +1290,13 @@ def _Backward2b_T_Ph(P, h): Pr = P/1 nu = h/2000 - T = 0 + T = 0.0 for i, j, ni in zip(I, J, n): T += ni * (Pr-2)**i * (nu-2.6)**j return T -def _Backward2c_T_Ph(P, h): +def _Backward2c_T_Ph(P: float, h: float) -> float: """Backward equation for region 2c, T=f(P,h) Parameters @@ -1339,13 +1339,13 @@ def _Backward2c_T_Ph(P, h): Pr = P/1 nu = h/2000 - T = 0 + T = 0.0 for i, j, ni in zip(I, J, n): T += ni * (Pr+25)**i * (nu-1.8)**j return T -def _Backward2_T_Ph(P, h): +def _Backward2_T_Ph(P: float, h: float) -> float: """Backward equation for region 2, T=f(P,h) Parameters @@ -1377,7 +1377,7 @@ def _Backward2_T_Ph(P, h): return T -def _Backward2a_T_Ps(P, s): +def _Backward2a_T_Ps(P: float, s: float) -> float: """Backward equation for region 2a, T=f(P,s) Parameters @@ -1431,13 +1431,13 @@ def _Backward2a_T_Ps(P, s): Pr = P/1 sigma = s/2 - T = 0 + T = 0.0 for i, j, ni in zip(I, J, n): T += ni * Pr**i * (sigma-2)**j return T -def _Backward2b_T_Ps(P, s): +def _Backward2b_T_Ps(P: float, s: float) -> float: """Backward equation for region 2b, T=f(P,s) Parameters @@ -1488,13 +1488,13 @@ def _Backward2b_T_Ps(P, s): Pr = P/1 sigma = s/0.7853 - T = 0 + T = 0.0 for i, j, ni in zip(I, J, n): T += ni * Pr**i * (10-sigma)**j return T -def _Backward2c_T_Ps(P, s): +def _Backward2c_T_Ps(P: float, s: float) -> float: """Backward equation for region 2c, T=f(P,s) Parameters @@ -1539,13 +1539,13 @@ def _Backward2c_T_Ps(P, s): Pr = P/1 sigma = s/2.9251 - T = 0 + T = 0.0 for i, j, ni in zip(I, J, n): T += ni * Pr**i * (2-sigma)**j return T -def _Backward2_T_Ps(P, s): +def _Backward2_T_Ps(P: float, s: float) -> float: """Backward equation for region 2, T=f(P,s) Parameters @@ -1573,7 +1573,7 @@ def _Backward2_T_Ps(P, s): return T -def _Backward2a_P_hs(h, s): +def _Backward2a_P_hs(h: float, s: float) -> float: """Backward equation for region 2a, P=f(h,s) Parameters @@ -1621,13 +1621,13 @@ def _Backward2a_P_hs(h, s): nu = h/4200 sigma = s/12 - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (nu-0.5)**i * (sigma-1.2)**j return 4*suma**4 -def _Backward2b_P_hs(h, s): +def _Backward2b_P_hs(h: float, s: float) -> float: """Backward equation for region 2b, P=f(h,s) Parameters @@ -1676,13 +1676,13 @@ def _Backward2b_P_hs(h, s): nu = h/4100 sigma = s/7.9 - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (nu-0.6)**i * (sigma-1.01)**j return 100*suma**4 -def _Backward2c_P_hs(h, s): +def _Backward2c_P_hs(h: float, s: float) -> float: """Backward equation for region 2c, P=f(h,s) Parameters @@ -1731,13 +1731,13 @@ def _Backward2c_P_hs(h, s): nu = h/3500 sigma = s/5.9 - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (nu-0.7)**i * (sigma-1.1)**j return 100*suma**4 -def _Backward2_P_hs(h, s): +def _Backward2_P_hs(h: float, s: float) -> float: """Backward equation for region 2, P=f(h,s) Parameters @@ -1764,7 +1764,7 @@ def _Backward2_P_hs(h, s): # Region 3 -def _Region3(rho, T): +def _Region3(rho: float, T: float) -> Dict[str, float]: """Basic equation for region 3 Parameters @@ -1839,7 +1839,7 @@ def _Region3(rho, T): g = 1.0658070028513*log(d) gd = 1.0658070028513/d gdd = -1.0658070028513/d**2 - gt = gtt = gdt = 0 + gt = gtt = gdt = 0.0 for i, j, ni in zip(I, J, n): g += ni * d**i * Tr**j gd += ni*i * d**(i-1) * Tr**j @@ -1887,7 +1887,7 @@ def _h_3ab(P): 0.0219921901054187*P**2+0.875131686009950e-4*P**3 -def _tab_P(P): +def _tab_P(P: float) -> float: """Define the boundary between Region 3a-3b, T=f(P) Parameters @@ -1917,13 +1917,13 @@ def _tab_P(P): -0.191887498864292e4, 0.918419702359447e3] Pr = P/1 - T = 0 + T = 0.0 for i, ni in zip(I, n): T += ni * log(Pr)**i return T -def _top_P(P): +def _top_P(P: float) -> float: """Define the boundary between Region 3o-3p, T=f(P) Parameters @@ -1953,13 +1953,13 @@ def _top_P(P): 0.773845935768222e3, -0.152313732937084e4] Pr = P/1 - T = 0 + T = 0.0 for i, ni in zip(I, n): T += ni * log(Pr)**i return T -def _twx_P(P): +def _twx_P(P: float) -> float: """Define the boundary between Region 3w-3x, T=f(P) Parameters @@ -1989,13 +1989,13 @@ def _twx_P(P): 0.329196213998375e3, 0.873371668682417e3] Pr = P/1 - T = 0 + T = 0.0 for i, ni in zip(I, n): T += ni * log(Pr)**i return T -def _tef_P(P): +def _tef_P(P: float) -> float: """Define the boundary between Region 3e-3f, T=f(P) Parameters @@ -2023,7 +2023,7 @@ def _tef_P(P): return 3.727888004*(P-22.064)+647.096 -def _txx_P(P, xy): +def _txx_P(P: float, xy: str) -> float: """Define the boundary between 3x-3y, T=f(P) Parameters @@ -2084,13 +2084,13 @@ def _txx_P(P, xy): n = ng[xy] Pr = P/1 - T = 0 + T = 0.0 for i, ni in enumerate(n): T += ni * Pr**i return T -def _Backward3a_v_Ph(P, h): +def _Backward3a_v_Ph(P: float, h: float) -> float: """Backward equation for region 3a, v=f(P,h) Parameters @@ -2137,13 +2137,13 @@ def _Backward3a_v_Ph(P, h): Pr = P/100 nu = h/2100 - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (Pr+0.128)**i * (nu-0.727)**j return 0.0028*suma -def _Backward3b_v_Ph(P, h): +def _Backward3b_v_Ph(P: float, h: float) -> float: """Backward equation for region 3b, v=f(P,h) Parameters @@ -2189,13 +2189,13 @@ def _Backward3b_v_Ph(P, h): Pr = P/100 nu = h/2800 - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (Pr+0.0661)**i * (nu-0.72)**j return 0.0088*suma -def _Backward3_v_Ph(P, h): +def _Backward3_v_Ph(P: float, h: float) -> float: """Backward equation for region 3, v=f(P,h) Parameters @@ -2217,7 +2217,7 @@ def _Backward3_v_Ph(P, h): return _Backward3b_v_Ph(P, h) -def _Backward3a_T_Ph(P, h): +def _Backward3a_T_Ph(P: float, h: float) -> float: """Backward equation for region 3a, T=f(P,h) Parameters @@ -2264,13 +2264,13 @@ def _Backward3a_T_Ph(P, h): Pr = P/100. nu = h/2300. - suma = 0 + suma = 0.0 for i, j, n in zip(I, J, n): suma += n*(Pr+0.240)**i*(nu-0.615)**j return 760*suma -def _Backward3b_T_Ph(P, h): +def _Backward3b_T_Ph(P: float, h: float) -> float: """Backward equation for region 3b, T=f(P,h) Parameters @@ -2317,13 +2317,13 @@ def _Backward3b_T_Ph(P, h): Pr = P/100. nu = h/2800. - suma = 0 + suma = 0.0 for i, j, n in zip(I, J, n): suma += n*(Pr+0.298)**i*(nu-0.72)**j return 860*suma -def _Backward3_T_Ph(P, h): +def _Backward3_T_Ph(P: float, h: float) -> float: """Backward equation for region 3, T=f(P,h) Parameters @@ -2346,7 +2346,7 @@ def _Backward3_T_Ph(P, h): return T -def _Backward3a_v_Ps(P, s): +def _Backward3a_v_Ps(P: float, s: float) -> float: """Backward equation for region 3a, v=f(P,s) Parameters @@ -2392,13 +2392,13 @@ def _Backward3a_v_Ps(P, s): Pr = P/100 sigma = s/4.4 - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (Pr+0.187)**i * (sigma-0.755)**j return 0.0028*suma -def _Backward3b_v_Ps(P, s): +def _Backward3b_v_Ps(P: float, s: float) -> float: """Backward equation for region 3b, v=f(P,s) Parameters @@ -2445,13 +2445,13 @@ def _Backward3b_v_Ps(P, s): Pr = P/100 sigma = s/5.3 - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (Pr+0.298)**i * (sigma-0.816)**j return 0.0088*suma -def _Backward3_v_Ps(P, s): +def _Backward3_v_Ps(P: float, s: float) -> float: """Backward equation for region 3, v=f(P,s) Parameters @@ -2472,7 +2472,7 @@ def _Backward3_v_Ps(P, s): return _Backward3b_v_Ps(P, s) -def _Backward3a_T_Ps(P, s): +def _Backward3a_T_Ps(P: float, s: float) -> float: """Backward equation for region 3a, T=f(P,s) Parameters @@ -2519,13 +2519,13 @@ def _Backward3a_T_Ps(P, s): Pr = P/100 sigma = s/4.4 - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (Pr+0.240)**i * (sigma-0.703)**j return 760*suma -def _Backward3b_T_Ps(P, s): +def _Backward3b_T_Ps(P: float, s: float) -> float: """Backward equation for region 3b, T=f(P,s) Parameters @@ -2571,13 +2571,13 @@ def _Backward3b_T_Ps(P, s): Pr = P/100 sigma = s/5.3 - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (Pr+0.760)**i * (sigma-0.818)**j return 860*suma -def _Backward3_T_Ps(P, s): +def _Backward3_T_Ps(P: float, s: float) -> float: """Backward equation for region 3, T=f(P,s) Parameters @@ -2600,7 +2600,7 @@ def _Backward3_T_Ps(P, s): return T -def _Backward3a_P_hs(h, s): +def _Backward3a_P_hs(h: float, s: float) -> float: """Backward equation for region 3a, P=f(h,s) Parameters @@ -2650,13 +2650,13 @@ def _Backward3a_P_hs(h, s): nu = h/2300 sigma = s/4.4 - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (nu-1.01)**i * (sigma-0.75)**j return 99*suma -def _Backward3b_P_hs(h, s): +def _Backward3b_P_hs(h: float, s: float) -> float: """Backward equation for region 3b, P=f(h,s) Parameters @@ -2708,13 +2708,13 @@ def _Backward3b_P_hs(h, s): nu = h/2800 sigma = s/5.3 - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (nu-0.681)**i * (sigma-0.792)**j return 16.6/suma -def _Backward3_P_hs(h, s): +def _Backward3_P_hs(h: float, s: float) -> float: """Backward equation for region 3, P=f(h,s) Parameters @@ -2736,7 +2736,7 @@ def _Backward3_P_hs(h, s): return _Backward3b_P_hs(h, s) -def _Backward3_sat_v_P(P, T, x): +def _Backward3_sat_v_P(P: float, T: float, x: int) -> float: """Backward equation for region 3 for saturated state, vs=f(P,x) Parameters @@ -2779,7 +2779,7 @@ def _Backward3_sat_v_P(P, T, x): return _Backward3x_v_PT(T, P, region) -def _Backward3_v_PT(P, T): +def _Backward3_v_PT(P: float, T: float) -> float: """Backward equation for region 3, v=f(P,T) Parameters @@ -2961,7 +2961,7 @@ def _Backward3_v_PT(P, T): return _Backward3x_v_PT(T, P, region) -def _Backward3x_v_PT(T, P, x): +def _Backward3x_v_PT(T: float, P: float, x: str) -> float: """Backward equation for region 3x, v=f(P,T) Parameters @@ -3558,7 +3558,7 @@ def _Backward3x_v_PT(T, P, x): Pr = P/P_ Tr = T/T_ - suma = 0 + suma = 0.0 if x == "n": for i, j, ni in zip(I, J, n): suma += ni * (Pr-a)**i * (Tr-b)**j @@ -3570,7 +3570,7 @@ def _Backward3x_v_PT(T, P, x): # Region 4 -def _Region4(P, x): +def _Region4(P: float, x: float) -> Dict[str, Optional[float]]: """Basic equation for region 4 Parameters @@ -3618,7 +3618,7 @@ def _Region4(P, x): return propiedades -def _Backward4_T_hs(h, s): +def _Backward4_T_hs(h: float, s: float) -> float: """Backward equation for region 4, T=f(h,s) Parameters @@ -3669,14 +3669,14 @@ def _Backward4_T_hs(h, s): nu = h/2800 sigma = s/9.2 - suma = 0 + suma = 0.0 for i, j, ni in zip(I, J, n): suma += ni * (nu-0.119)**i * (sigma-1.07)**j return 550*suma # Region 5 -def _Region5(T, P): +def _Region5(T: float, P: float) -> Dict[str, float]: """Basic equation for region 5 Parameters @@ -3739,7 +3739,7 @@ def _Region5(T, P): Jr = [1, 2, 3, 3, 9, 7] nr = [0.15736404855259e-2, 0.90153761673944e-3, -0.50270077677648e-2, 0.22440037409485e-5, -0.41163275453471e-5, 0.37919454822955e-7] - gr = grp = grpp = grt = grtt = grpt = 0 + gr = grp = grpp = grt = grtt = grpt = 0.0 for i, j, ni in zip(Ir, Jr, nr): gr += ni * Pr**i * Tr**j grp += ni*i * Pr**(i-1) * Tr**j @@ -3766,7 +3766,7 @@ def _Region5(T, P): return propiedades -def Region5_cp0(Tr, Pr): +def Region5_cp0(Tr: float, Pr: float) -> Tuple[float, float, float, float, float, float]: """Ideal properties for Region 5 Parameters @@ -3800,7 +3800,7 @@ def Region5_cp0(Tr, Pr): go = log(Pr) gop = Pr**-1 gopp = -Pr**-2 - got = gott = gopt = 0 + got = gott = gopt = 0.0 for j, ni in zip(Jo, no): go += ni * Tr**j got += ni*j * Tr**(j-1) @@ -3810,7 +3810,7 @@ def Region5_cp0(Tr, Pr): # Region definitions -def _Bound_TP(T, P): +def _Bound_TP(T: float, P: float) -> Optional[int]: """Region definition for input T and P Parameters @@ -3851,7 +3851,7 @@ def _Bound_TP(T, P): return region -def _Bound_Ph(P, h): +def _Bound_Ph(P: float, h: float) -> Optional[int]: """Region definition for input P y h Parameters @@ -3925,7 +3925,7 @@ def _Bound_Ph(P, h): return region -def _Bound_Ps(P, s): +def _Bound_Ps(P: float, s: float) -> Optional[int]: """Region definition for input P and s Parameters @@ -3999,7 +3999,7 @@ def _Bound_Ps(P, s): return region -def _Bound_hs(h, s): +def _Bound_hs(h: float, s: float) -> float: """Region definition for input h and s Parameters @@ -4171,7 +4171,7 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return region -def prop0(T, P): +def prop0(T: float, P: float) -> Dict[str, float]: """Ideal gas properties Parameters @@ -4340,7 +4340,7 @@ def __call__(self, **kwargs): self.msg = "Solved" @property - def calculable(self): + def calculable(self) -> str: """Check if class is calculable by its kwargs""" self._thermo = "" if self.kwargs["T"] and self.kwargs["P"]: @@ -4682,7 +4682,7 @@ def rho_funcion(rho: float) -> float: self.Hvap = vapor["h"]-liquido["h"] self.Svap = vapor["s"]-liquido["s"] - def fill(self, fase, estado): + def fill(self, fase, estado: Dict[str, float]): """Fill phase properties""" fase.v = estado["v"] fase.rho = 1/fase.v @@ -4731,7 +4731,7 @@ def fill(self, fase, estado): except NotImplementedError: fase.n = None - def derivative(self, z, x, y, fase): + def derivative(self, z: str, x: str, y: str, fase): """ Wrapper derivative for custom derived properties where x, y, z can be: P, T, v, u, h, s, g, a @@ -4742,33 +4742,33 @@ def derivative(self, z, x, y, fase): class IAPWS97_PT(IAPWS97): """Derivated class for direct P and T input""" - def __init__(self, P, T): + def __init__(self, P: float, T: float): IAPWS97.__init__(self, T=T, P=P) class IAPWS97_Ph(IAPWS97): """Derivated class for direct P and h input""" - def __init__(self, P, h): + def __init__(self, P: float, h: float): IAPWS97.__init__(self, P=P, h=h) class IAPWS97_Ps(IAPWS97): """Derivated class for direct P and s input""" - def __init__(self, P, s): + def __init__(self, P: float, s: float): IAPWS97.__init__(self, P=P, s=s) class IAPWS97_Px(IAPWS97): """Derivated class for direct P and x input""" - def __init__(self, P, x): + def __init__(self, P: float, x): IAPWS97.__init__(self, P=P, x=x) class IAPWS97_Tx(IAPWS97): """Derivated class for direct T and x input""" - def __init__(self, T, x): + def __init__(self, T: float, x): IAPWS97.__init__(self, T=T, x=x) From f6150a724ee66541d9c31eea2270f10a5f4b98e0 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sun, 14 Mar 2021 03:53:42 -0400 Subject: [PATCH 032/102] Make a couple of assertions to help mypy. The assertions help mypy know that these can't be None. They can't be... right? If there were we seem destined for a backtrace anyway. --- iapws/iapws08.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iapws/iapws08.py b/iapws/iapws08.py index 398c4cf..288fc27 100644 --- a/iapws/iapws08.py +++ b/iapws/iapws08.py @@ -264,6 +264,8 @@ def derivative(self, z: str, x: str, y: str): def _water(cls, T: float, P: float) -> Dict[str, float]: """Get properties of pure water, Table4 pag 8""" water = IAPWS95(P=P, T=T) + assert(isinstance(water.h, float)) + assert(isinstance(water.s, float)) prop = {} prop["g"] = water.h-T*water.s prop["gt"] = -water.s From e4229239472d0d482d787568f7abef62a0e0b4a1 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sun, 14 Mar 2021 03:55:21 -0400 Subject: [PATCH 033/102] Tell mypy that a couple of variables exist... Where are they set though? Also convert a missed suma to float. --- iapws/iapws95.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 4c5ff33..5badb71 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -395,6 +395,8 @@ class MEoS(_fase): # is a little messy. By statically typing them here, we at least # let mypy know that they're supposed to be set... rhoc: float + Tc: float + Pc: float _constants: Dict[str, List[float]] def __init__(self, **kwargs): @@ -2106,7 +2108,7 @@ def _Vapor_Pressure(cls, T: float) -> float: http://www.iapws.org/relguide/Supp-sat.html, Eq.1 """ Tita = 1-T/cls.Tc - suma = 0 + suma = 0.0 for n, x in zip(cls._Pv["ao"], cls._Pv["exp"]): suma += n*Tita**x Pr = exp(cls.Tc/T*suma) From d047187196aebc6b74c41226fdb3f8eac96d8ed5 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sun, 14 Mar 2021 03:56:30 -0400 Subject: [PATCH 034/102] A few more assertions to help mypy. There can probably be moved to a better location though. Also convert another suma to float. --- iapws/humidAir.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/iapws/humidAir.py b/iapws/humidAir.py index 987aea3..67a2916 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -356,7 +356,7 @@ def _Liquid_Density(cls, T: float) -> float: Ni = [44.3413, -240.073, 285.139, -88.3366] ti = [0.65, 0.85, 0.95, 1.1] Tita = 1-T/Tc - suma = 1 + suma = 1.0 for n, t in zip(Ni, ti): suma += n*Tita**t suma -= 0.892181*log(T/Tc) @@ -641,20 +641,25 @@ def calculo(self) -> None: A = self.kwargs["A"] elif self._composition == "xa": xa = self.kwargs["xa"] + assert(isinstance(xa, float)) A = xa/(1-(1-xa)*(1-MW/Ma)) # Thermodynamic definition if self._mode == "TP": + def rho_func(rho: float) -> float: fav = self._fav(T, rho, A) return rho**2*fav["fird"]/1000-P rho = fsolve(rho_func, 1)[0] elif self._mode == "Prho": + def t_func(T: float) -> float: fav = self._fav(T, rho, A) return rho**2*fav["fird"]/1000-P T = fsolve(t_func, 300)[0] + assert(isinstance(rho, float)) + assert(isinstance(A, float)) # General calculation procedure fav = self._fav(T, rho, A) From 2cf70a5f46a4805769affb925ebd627de6d02e3e Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sun, 14 Mar 2021 12:41:47 -0400 Subject: [PATCH 035/102] Some gentle variable renaming to allow mypy to do type analysis. nb was reused with two different types, and the Fi0 dict, while probably having some semantic significance mostly grouped together several variables with differing types. Using an object with members would be a fine solution, and I may explore that later. --- iapws/ammonia.py | 57 ++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/iapws/ammonia.py b/iapws/ammonia.py index 5518548..4ed7102 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -183,9 +183,9 @@ def _thermo(self, rho: float, T: float, fase) -> Optional[float]: # Critical enchancement t = abs(T-405.4)/405.4 dPT = 1e5*(2.18-0.12/exp(17.8*t)) - nb = 1e-5*(2.6+1.6*t) + nbx = 1e-5*(2.6+1.6*t) - DL = 1.2*Boltzmann*T**2/6/pi/nb/(1.34e-10/t**0.63*(1+t**0.5))*dPT**2 * \ + DL = 1.2*Boltzmann*T**2/6/pi/nbx/(1.34e-10/t**0.63*(1+t**0.5))*dPT**2 * \ 0.423e-8/t**1.24*(1+t**0.5/0.7) # Add correction for entire range of temperature, Eq 10 @@ -326,45 +326,44 @@ def _phi0(self, rho: float, T: float, x: float) -> Dict[str, float]: tau = 500/T delta = rho/15/M - # Table 2 - Fi0 = { - "log_water": 3.006320, - "ao_water": [-7.720435, 8.649358], - "pow_water": [0, 1], - "ao_exp": [0.012436, 0.97315, 1.279500, 0.969560, 0.248730], - "titao": [1.666, 4.578, 10.018, 11.964, 35.600], - "log_nh3": -1.0, - "ao_nh3": [-16.444285, 4.036946, 10.69955, -1.775436, 0.82374034], - "pow_nh3": [0, 1, 1/3, -3/2, -7/4]} + # Table 2, previously an Fi0 dict + log_water = 3.006320 + ao_water = [-7.720435, 8.649358] + pow_water = [0, 1] + ao_exp = [0.012436, 0.97315, 1.279500, 0.969560, 0.248730] + titao = [1.666, 4.578, 10.018, 11.964, 35.600] + log_nh3 = -1.0 + ao_nh3 = [-16.444285, 4.036946, 10.69955, -1.775436, 0.82374034] + pow_nh3 = [0.0, 1.0, 1/3, -3/2, -7/4] fiod = 1/delta fiodd = -1/delta**2 - fiodt = 0 - fiow = fiotw = fiottw = 0 - fioa = fiota = fiotta = 0 + fiodt = 0.0 + fiow = fiotw = fiottw = 0.0 + fioa = fiota = fiotta = 0.0 # Water section if x < 1: - fiow = Fi0["log_water"]*log(tau) + log(1-x) - fiotw = Fi0["log_water"]/tau - fiottw = -Fi0["log_water"]/tau**2 - for n, t in zip(Fi0["ao_water"], Fi0["pow_water"]): - fiow += n*tau**t - if t != 0: - fiotw += t*n*tau**(t-1) - if t not in [0, 1]: - fiottw += n*t*(t-1)*tau**(t-2) - for n, t in zip(Fi0["ao_exp"], Fi0["titao"]): + fiow = log_water*log(tau) + log(1-x) + fiotw = log_water/tau + fiottw = -log_water/tau**2 + for n, ti in zip(ao_water, pow_water): + fiow += n*tau**ti + if ti != 0: + fiotw += ti*n*tau**(ti-1) + if ti not in [0, 1]: + fiottw += n*ti*(ti-1)*tau**(ti-2) + for n, t in zip(ao_exp, titao): fiow += n*log(1-exp(-tau*t)) fiotw += n*t*((1-exp(-t*tau))**-1-1) fiottw -= n*t**2*exp(-t*tau)*(1-exp(-t*tau))**-2 # ammonia section if x > 0: - fioa = Fi0["log_nh3"]*log(tau) + log(x) - fiota = Fi0["log_nh3"]/tau - fiotta = -Fi0["log_nh3"]/tau**2 - for n, t in zip(Fi0["ao_nh3"], Fi0["pow_nh3"]): + fioa = log_nh3*log(tau) + log(x) + fiota = log_nh3/tau + fiotta = -log_nh3/tau**2 + for n, t in zip(ao_nh3, pow_nh3): fioa += n*tau**t if t != 0: fiota += t*n*tau**(t-1) From 18c4cff61b3da5a71260c72feab971e8eb88e375 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sun, 14 Mar 2021 12:46:13 -0400 Subject: [PATCH 036/102] Explicitly mark some variables as floats. --- iapws/_iapws.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iapws/_iapws.py b/iapws/_iapws.py index b480385..ffb598f 100644 --- a/iapws/_iapws.py +++ b/iapws/_iapws.py @@ -612,7 +612,7 @@ def _Sublimation_Pressure(T: float) -> float: """ if 50 <= T <= 273.16: Tita = T/Tt - suma = 0 + suma = 0.0 a = [-0.212144006e2, 0.273203819e2, -0.61059813e1] expo = [0.333333333e-2, 1.20666667, 1.70333333] for ai, expi in zip(a, expo): @@ -664,7 +664,7 @@ def _Melting_Pressure(T: float, ice: str = "Ih") -> float: Tita = T/Tref a = [0.119539337e7, 0.808183159e5, 0.33382686e4] expo = [3., 0.2575e2, 0.10375e3] - suma = 1 + suma = 1.0 for ai, expi in zip(a, expo): suma += ai*(1-Tita**expi) P = suma*Pref @@ -1092,7 +1092,7 @@ def _Kw(rho: float, T: float) -> float: Mw = 18.015268 gamma = [6.1415e-1, 4.825133e4, -6.770793e4, 1.01021e7] - pKg = 0 + pKg = 0.0 for i, g in enumerate(gamma): pKg += g/T**i @@ -1323,7 +1323,7 @@ def _D2O_Sublimation_Pressure(T: float) -> float: """ if 210 <= T <= 276.969: Tita = T/276.969 - suma = 0 + suma = 0.0 ai = [-0.1314226e2, 0.3212969e2] ti = [-1.73, -1.42] for a, t in zip(ai, ti): @@ -1373,7 +1373,7 @@ def _D2O_Melting_Pressure(T: float, ice: str = "Ih") -> float: Tita = T/276.969 ai = [-0.30153e5, 0.692503e6] ti = [5.5, 8.2] - suma = 1 + suma = 1.0 for a, t in zip(ai, ti): suma += a*(1-Tita**t) P = suma*0.00066159 From 4e9fecface41783c0789c9a14fa7a0295f2240ea Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sun, 14 Mar 2021 18:21:14 -0400 Subject: [PATCH 037/102] A rather messy case where None is used in float lists. This is one way to address the issue. but certainly not the only one. --- iapws/_iapws.py | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/iapws/_iapws.py b/iapws/_iapws.py index ffb598f..6ebd5ab 100644 --- a/iapws/_iapws.py +++ b/iapws/_iapws.py @@ -278,18 +278,20 @@ def _Liquid(T: float, P: float = 0.1) -> Dict[str, float]: alfa = Tr/(593-T) beta = Tr/(T-232) - a = [None, -1.661470539e5, 2.708781640e6, -1.557191544e8, None, + FNONE = 0.0 + a = [FNONE, -1.661470539e5, 2.708781640e6, -1.557191544e8, FNONE, 1.93763157e-2, 6.74458446e3, -2.22521604e5, 1.00231247e8, -1.63552118e9, 8.32299658e9, -7.5245878e-6, -1.3767418e-2, 1.0627293e1, -2.0457795e2, 1.2037414e3] - b = [None, -8.237426256e-1, 1.908956353, -2.017597384, 8.546361348e-1, + b = [FNONE, -8.237426256e-1, 1.908956353, -2.017597384, 8.546361348e-1, 5.78545292e-3, -1.53195665E-2, 3.11337859e-2, -4.23546241e-2, 3.38713507e-2, -1.19946761e-2, -3.1091470e-6, 2.8964919e-5, -1.3112763e-4, 3.0410453e-4, -3.9034594e-4, 2.3403117e-4, -4.8510101e-5] - c = [None, -2.452093414e2, 3.869269598e1, -8.983025854] - n = [None, 4, 5, 7, None, None, 4, 5, 7, 8, 9, 1, 3, 5, 6, 7] - m = [None, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 1, 3, 4, 5, 6, 7, 9] + c = [FNONE, -2.452093414e2, 3.869269598e1, -8.983025854] + # Zero entries are not used or present in the table. + n = [0, 4, 5, 7, 0, 0, 4, 5, 7, 8, 9, 1, 3, 5, 6, 7] + m = [0, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 1, 3, 4, 5, 6, 7, 9] suma1 = sum(a[i]*alfa**n[i] for i in range(1, 4)) suma2 = sum(b[i]*beta**m[i] for i in range(1, 5)) @@ -336,8 +338,8 @@ def _Liquid(T: float, P: float = 0.1) -> Dict[str, float]: h = go+T*so u = h-P*vo - a = go-P*vo - cv = cpo+T*vto**2/vpo + a_result = go-P*vo + local_cv = cpo+T*vto**2/vpo xkappa = -vpo/vo alfa = vto/vo ks = -(T*vto**2/cpo+vpo)/vo @@ -356,30 +358,30 @@ def _Liquid(T: float, P: float = 0.1) -> Dict[str, float]: propiedades["h"] = h propiedades["s"] = so propiedades["cp"] = cpo - propiedades["cv"] = cv + propiedades["cv"] = local_cv propiedades["u"] = u - propiedades["a"] = a + propiedades["a"] = a_result propiedades["xkappa"] = xkappa propiedades["alfav"] = vto/vo propiedades["ks"] = ks propiedades["w"] = w # Viscosity correlation, Eq 7 - a = [None, 280.68, 511.45, 61.131, 0.45903] - b = [None, -1.9, -7.7, -19.6, -40] + a = [FNONE, 280.68, 511.45, 61.131, 0.45903] + b = [FNONE, -1.9, -7.7, -19.6, -40] T_ = T/300 mu = sum(a[i]*T_**b[i] for i in range(1, 5))/1e6 propiedades["mu"] = mu # Thermal conductivity correlation, Eq 8 - c = [None, 1.6630, -1.7781, 1.1567, -0.432115] - d = [None, -1.15, -3.4, -6.0, -7.6] + c = [FNONE, 1.6630, -1.7781, 1.1567, -0.432115] + d = [FNONE, -1.15, -3.4, -6.0, -7.6] k = sum(c[i]*T_**d[i] for i in range(1, 5)) propiedades["k"] = k # Dielectric constant correlation, Eq 9 - e = [None, -43.7527, 299.504, -399.364, 221.327] - f = [None, -0.05, -1.47, -2.11, -2.31] + e = [FNONE, -43.7527, 299.504, -399.364, 221.327] + f = [FNONE, -0.05, -1.47, -2.11, -2.31] epsilon = sum(e[i]*T_**f[i] for i in range(1, 5)) propiedades["epsilon"] = epsilon From d3a46274b51c12bbd4f499713aae98f2e9a104bd Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sun, 14 Mar 2021 18:37:05 -0400 Subject: [PATCH 038/102] An alternative approach to the previous commit using zero indexing. This code is equivalent and removes the need for unused entries with zero indexing. I think it's cleaner, but both commits work. --- iapws/_iapws.py | 69 ++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/iapws/_iapws.py b/iapws/_iapws.py index 6ebd5ab..0b22626 100644 --- a/iapws/_iapws.py +++ b/iapws/_iapws.py @@ -278,53 +278,52 @@ def _Liquid(T: float, P: float = 0.1) -> Dict[str, float]: alfa = Tr/(593-T) beta = Tr/(T-232) - FNONE = 0.0 - a = [FNONE, -1.661470539e5, 2.708781640e6, -1.557191544e8, FNONE, + a = [-1.661470539e5, 2.708781640e6, -1.557191544e8, 0.0, 1.93763157e-2, 6.74458446e3, -2.22521604e5, 1.00231247e8, -1.63552118e9, 8.32299658e9, -7.5245878e-6, -1.3767418e-2, 1.0627293e1, -2.0457795e2, 1.2037414e3] - b = [FNONE, -8.237426256e-1, 1.908956353, -2.017597384, 8.546361348e-1, + b = [-8.237426256e-1, 1.908956353, -2.017597384, 8.546361348e-1, 5.78545292e-3, -1.53195665E-2, 3.11337859e-2, -4.23546241e-2, 3.38713507e-2, -1.19946761e-2, -3.1091470e-6, 2.8964919e-5, -1.3112763e-4, 3.0410453e-4, -3.9034594e-4, 2.3403117e-4, -4.8510101e-5] - c = [FNONE, -2.452093414e2, 3.869269598e1, -8.983025854] + c = [-2.452093414e2, 3.869269598e1, -8.983025854] # Zero entries are not used or present in the table. - n = [0, 4, 5, 7, 0, 0, 4, 5, 7, 8, 9, 1, 3, 5, 6, 7] - m = [0, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 1, 3, 4, 5, 6, 7, 9] + n = [4, 5, 7, 0, 0, 4, 5, 7, 8, 9, 1, 3, 5, 6, 7] + m = [2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 1, 3, 4, 5, 6, 7, 9] - suma1 = sum(a[i]*alfa**n[i] for i in range(1, 4)) - suma2 = sum(b[i]*beta**m[i] for i in range(1, 5)) - go = R*Tr*(c[1]+c[2]*tau+c[3]*tau*log(tau)+suma1+suma2) + suma1 = sum(a[i]*alfa**n[i] for i in range(0, 3)) + suma2 = sum(b[i]*beta**m[i] for i in range(0, 4)) + go = R*Tr*(c[0]+c[1]*tau+c[2]*tau*log(tau)+suma1+suma2) - suma1 = sum(a[i]*alfa**n[i] for i in range(6, 11)) - suma2 = sum(b[i]*beta**m[i] for i in range(5, 11)) - vo = R*Tr/Po/1000*(a[5]+suma1+suma2) + suma1 = sum(a[i]*alfa**n[i] for i in range(5, 10)) + suma2 = sum(b[i]*beta**m[i] for i in range(4, 10)) + vo = R*Tr/Po/1000*(a[4]+suma1+suma2) - suma1 = sum(a[i]*alfa**n[i] for i in range(11, 16)) - suma2 = sum(b[i]*beta**m[i] for i in range(11, 18)) + suma1 = sum(a[i]*alfa**n[i] for i in range(10, 15)) + suma2 = sum(b[i]*beta**m[i] for i in range(10, 17)) vpo = R*Tr/Po**2/1000*(suma1+suma2) - suma1 = sum(n[i]*a[i]*alfa**(n[i]+1) for i in range(1, 4)) - suma2 = sum(m[i]*b[i]*beta**(m[i]+1) for i in range(1, 5)) - so = -R*(c[2]+c[3]*(1+log(tau))+suma1-suma2) + suma1 = sum(n[i]*a[i]*alfa**(n[i]+1) for i in range(0, 3)) + suma2 = sum(m[i]*b[i]*beta**(m[i]+1) for i in range(0, 4)) + so = -R*(c[1]+c[2]*(1+log(tau))+suma1-suma2) - suma1 = sum(n[i]*(n[i]+1)*a[i]*alfa**(n[i]+2) for i in range(1, 4)) - suma2 = sum(m[i]*(m[i]+1)*b[i]*beta**(m[i]+2) for i in range(1, 5)) - cpo = -R*(c[3]+tau*suma1+tau*suma2) + suma1 = sum(n[i]*(n[i]+1)*a[i]*alfa**(n[i]+2) for i in range(0, 3)) + suma2 = sum(m[i]*(m[i]+1)*b[i]*beta**(m[i]+2) for i in range(0, 4)) + cpo = -R*(c[2]+tau*suma1+tau*suma2) - suma1 = sum(n[i]*a[i]*alfa**(n[i]+1) for i in range(6, 11)) - suma2 = sum(m[i]*b[i]*beta**(m[i]+1) for i in range(5, 11)) + suma1 = sum(n[i]*a[i]*alfa**(n[i]+1) for i in range(5, 10)) + suma2 = sum(m[i]*b[i]*beta**(m[i]+1) for i in range(4, 10)) vto = R/Po/1000*(suma1-suma2) # This properties are only neccessary for computing thermodynamic # properties at pressures different from 0.1 MPa - suma1 = sum(n[i]*(n[i]+1)*a[i]*alfa**(n[i]+2) for i in range(6, 11)) - suma2 = sum(m[i]*(m[i]+1)*b[i]*beta**(m[i]+2) for i in range(5, 11)) + suma1 = sum(n[i]*(n[i]+1)*a[i]*alfa**(n[i]+2) for i in range(5, 10)) + suma2 = sum(m[i]*(m[i]+1)*b[i]*beta**(m[i]+2) for i in range(4, 10)) vtto = R/Tr/Po/1000*(suma1+suma2) - suma1 = sum(n[i]*a[i]*alfa**(n[i]+1) for i in range(11, 16)) - suma2 = sum(m[i]*b[i]*beta**(m[i]+1) for i in range(11, 18)) + suma1 = sum(n[i]*a[i]*alfa**(n[i]+1) for i in range(10, 15)) + suma2 = sum(m[i]*b[i]*beta**(m[i]+1) for i in range(10, 17)) vpto = R/Po**2/1000*(suma1-suma2) if P != 0.1: @@ -367,22 +366,22 @@ def _Liquid(T: float, P: float = 0.1) -> Dict[str, float]: propiedades["w"] = w # Viscosity correlation, Eq 7 - a = [FNONE, 280.68, 511.45, 61.131, 0.45903] - b = [FNONE, -1.9, -7.7, -19.6, -40] + a = [280.68, 511.45, 61.131, 0.45903] + b = [-1.9, -7.7, -19.6, -40] T_ = T/300 - mu = sum(a[i]*T_**b[i] for i in range(1, 5))/1e6 + mu = sum(a[i]*T_**b[i] for i in range(0, 4))/1e6 propiedades["mu"] = mu # Thermal conductivity correlation, Eq 8 - c = [FNONE, 1.6630, -1.7781, 1.1567, -0.432115] - d = [FNONE, -1.15, -3.4, -6.0, -7.6] - k = sum(c[i]*T_**d[i] for i in range(1, 5)) + c = [1.6630, -1.7781, 1.1567, -0.432115] + d = [-1.15, -3.4, -6.0, -7.6] + k = sum(c[i]*T_**d[i] for i in range(0, 4)) propiedades["k"] = k # Dielectric constant correlation, Eq 9 - e = [FNONE, -43.7527, 299.504, -399.364, 221.327] - f = [FNONE, -0.05, -1.47, -2.11, -2.31] - epsilon = sum(e[i]*T_**f[i] for i in range(1, 5)) + e = [-43.7527, 299.504, -399.364, 221.327] + f = [-0.05, -1.47, -2.11, -2.31] + epsilon = sum(e[i]*T_**f[i] for i in range(0, 4)) propiedades["epsilon"] = epsilon return propiedades From ed5fc655ba049b3aa18811060ab68f82f081d71c Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sun, 14 Mar 2021 18:42:17 -0400 Subject: [PATCH 039/102] Change confusing reuse of variable names. These cases are good examples of the kinds of issues that prompted me to use mypy in the first place. It's just too easy to get confused about which variable is in scope and what type it is. --- iapws/iapws97.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iapws/iapws97.py b/iapws/iapws97.py index a80a2a1..28ae7c0 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -2250,7 +2250,7 @@ def _Backward3a_T_Ph(P: float, h: float) -> float: -5, -3, -2, -2, -2, -1, -1, 0, 0, 1, 3, 3, 4, 4, 10, 12] J = [0, 1, 2, 6, 14, 16, 20, 22, 1, 5, 12, 0, 2, 4, 10, 2, 0, 1, 3, 4, 0, 2, 0, 1, 1, 0, 1, 0, 3, 4, 5] - n = [-0.133645667811215e-6, 0.455912656802978e-5, -0.146294640700979e-4, + N = [-0.133645667811215e-6, 0.455912656802978e-5, -0.146294640700979e-4, 0.639341312970080e-2, 0.372783927268847e3, -0.718654377460447e4, 0.573494752103400e6, -0.267569329111439e7, -0.334066283302614e-4, -0.245479214069597e-1, 0.478087847764996e2, 0.764664131818904e-5, @@ -2265,7 +2265,7 @@ def _Backward3a_T_Ph(P: float, h: float) -> float: Pr = P/100. nu = h/2300. suma = 0.0 - for i, j, n in zip(I, J, n): + for i, j, n in zip(I, J, N): suma += n*(Pr+0.240)**i*(nu-0.615)**j return 760*suma From edaa12199708a53527a8ff46737db91161777031 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sun, 14 Mar 2021 19:02:38 -0400 Subject: [PATCH 040/102] Use then I, J, N and i, j, n code pattern more consistently. At first I thought the ni variable name was introduced by me to resolve an earlier mypy problem, and by the time I realized it wasn't it seemed wasteful not to go ahead and commit this consistency improving change. --- iapws/iapws97.py | 248 +++++++++++++++++++++++------------------------ 1 file changed, 122 insertions(+), 126 deletions(-) diff --git a/iapws/iapws97.py b/iapws/iapws97.py index 28ae7c0..bb6976e 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -145,12 +145,12 @@ def _h13_s(s: float) -> float: sigma = s/3.8 I = [0, 1, 1, 3, 5, 6] J = [0, -2, 2, -12, -4, -3] - n = [0.913965547600543, -0.430944856041991e-4, 0.603235694765419e2, + N = [0.913965547600543, -0.430944856041991e-4, 0.603235694765419e2, 0.117518273082168e-17, 0.220000904781292, -0.690815545851641e2] suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (sigma-0.884)**i * (sigma-0.864)**j + for i, j, n in zip(I, J, N): + suma += n * (sigma-0.884)**i * (sigma-0.864)**j return 1700 * suma @@ -259,7 +259,7 @@ def _t_hs(h: float, s: float) -> float: 8, 12, 12, 14, 14] J = [10, 8, 3, 4, 3, -6, 2, 3, 4, 0, -3, -2, 10, -2, -1, -5, -6, -3, -8, -2, -1, -12, -1, -12, 1] - n = [0.629096260829810e-3, -0.823453502583165e-3, 0.515446951519474e-7, + N = [0.629096260829810e-3, -0.823453502583165e-3, 0.515446951519474e-7, -0.117565945784945e1, 0.348519684726192e1, -0.507837382408313e-11, -0.284637670005479e1, -0.236092263939673e1, 0.601492324973779e1, 0.148039650824546e1, 0.360075182221907e-3, -0.126700045009952e-1, @@ -270,8 +270,8 @@ def _t_hs(h: float, s: float) -> float: 0.783237062349385e7] suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (nu-0.727)**i * (sigma-0.864)**j + for i, j, n in zip(I, J, N): + suma += n * (nu-0.727)**i * (sigma-0.864)**j return 900*suma @@ -409,15 +409,15 @@ def _PSat_h(h: float) -> float: nu = h/2600 I = [0, 1, 1, 1, 1, 5, 7, 8, 14, 20, 22, 24, 28, 36] J = [0, 1, 3, 4, 36, 3, 0, 24, 16, 16, 3, 18, 8, 24] - n = [0.600073641753024, -0.936203654849857e1, 0.246590798594147e2, + N = [0.600073641753024, -0.936203654849857e1, 0.246590798594147e2, -0.107014222858224e3, -0.915821315805768e14, -0.862332011700662e4, -0.235837344740032e2, 0.252304969384128e18, -0.389718771997719e19, -0.333775713645296e23, 0.356499469636328e11, -0.148547544720641e27, 0.330611514838798e19, 0.813641294467829e38] suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (nu-1.02)**i * (nu-0.608)**j + for i, j, n in zip(I, J, N): + suma += n * (nu-1.02)**i * (nu-0.608)**j return 22*suma @@ -463,14 +463,14 @@ def _PSat_s(s: float) -> float: sigma = s/5.2 I = [0, 1, 1, 4, 12, 12, 16, 24, 28, 32] J = [0, 1, 32, 7, 4, 14, 36, 10, 0, 18] - n = [0.639767553612785, -0.129727445396014e2, -0.224595125848403e16, + N = [0.639767553612785, -0.129727445396014e2, -0.224595125848403e16, 0.177466741801846e7, 0.717079349571538e10, -0.378829107169011e18, -0.955586736431328e35, 0.187269814676188e24, 0.119254746466473e12, 0.110649277244882e37] suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (sigma-1.03)**i * (sigma-0.699)**j + for i, j, n in zip(I, J, N): + suma += n * (sigma-1.03)**i * (sigma-0.699)**j return 22*suma @@ -517,7 +517,7 @@ def _h1_s(s: float) -> float: 20, 22, 24, 28, 32, 32] J = [14, 36, 3, 16, 0, 5, 4, 36, 4, 16, 24, 18, 24, 1, 4, 2, 4, 1, 22, 10, 12, 28, 8, 3, 0, 6, 8] - n = [0.332171191705237, 0.611217706323496e-3, -0.882092478906822e1, + N = [0.332171191705237, 0.611217706323496e-3, -0.882092478906822e1, -0.455628192543250, -0.263483840850452e-4, -0.223949661148062e2, -0.428398660164013e1, -0.616679338856916, -0.146823031104040e2, 0.284523138727299e3, -0.113398503195444e3, 0.115671380760859e4, @@ -528,8 +528,8 @@ def _h1_s(s: float) -> float: 0.834596332878346e-6, 0.503611916682674e1, 0.655444787064505e2] suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (sigma-1.09)**i * (sigma+0.366e-4)**j + for i, j, n in zip(I, J, N): + suma += n * (sigma-1.09)**i * (sigma+0.366e-4)**j return 1700*suma @@ -574,7 +574,7 @@ def _h3a_s(s: float) -> float: sigma = s/3.8 I = [0, 0, 0, 0, 2, 3, 4, 4, 5, 5, 6, 7, 7, 7, 10, 10, 10, 32, 32] J = [1, 4, 10, 16, 1, 36, 3, 16, 20, 36, 4, 2, 28, 32, 14, 32, 36, 0, 6] - n = [0.822673364673336, 0.181977213534479, -0.112000260313624e-1, + N = [0.822673364673336, 0.181977213534479, -0.112000260313624e-1, -0.746778287048033e-3, -0.179046263257381, 0.424220110836657e-1, -0.341355823438768, -0.209881740853565e1, -0.822477343323596e1, -0.499684082076008e1, 0.191413958471069, 0.581062241093136e-1, @@ -583,8 +583,8 @@ def _h3a_s(s: float) -> float: 0.631052532240980] suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (sigma-1.09)**i * (sigma+0.366e-4)**j + for i, j, n in zip(I, J, N): + suma += n * (sigma-1.09)**i * (sigma+0.366e-4)**j return 1700*suma @@ -632,7 +632,7 @@ def _h2ab_s(s: float) -> float: 32, 32, 32, 32, 32, 36, 36, 36, 36, 36] J = [8, 24, 4, 32, 1, 2, 7, 5, 12, 1, 0, 7, 10, 12, 32, 8, 12, 20, 22, 24, 2, 7, 12, 14, 24, 10, 12, 20, 22, 28] - n = [-0.524581170928788e3, -0.926947218142218e7, -0.237385107491666e3, + N = [-0.524581170928788e3, -0.926947218142218e7, -0.237385107491666e3, 0.210770155812776e11, -0.239494562010986e2, 0.221802480294197e3, -0.510472533393438e7, 0.124981396109147e7, 0.200008436996201e10, -0.815158509791035e3, -0.157612685637523e3, -0.114200422332791e11, @@ -644,8 +644,8 @@ def _h2ab_s(s: float) -> float: -0.175407764869978e33, 0.347581490626396e35, -0.710971318427851e39] suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (1/sigma1-0.513)**i * (sigma2-0.524)**j + for i, j, n in zip(I, J, N): + suma += n * (1/sigma1-0.513)**i * (sigma2-0.524)**j return 2800*exp(suma) @@ -690,7 +690,7 @@ def _h2c3b_s(s: float) -> float: sigma = s/5.9 I = [0, 0, 0, 1, 1, 5, 6, 7, 8, 8, 12, 16, 22, 22, 24, 36] J = [0, 3, 4, 0, 12, 36, 12, 16, 2, 20, 32, 36, 2, 32, 7, 20] - n = [0.104351280732769e1, -0.227807912708513e1, 0.180535256723202e1, + N = [0.104351280732769e1, -0.227807912708513e1, 0.180535256723202e1, 0.420440834792042, -0.105721244834660e6, 0.436911607493884e25, -0.328032702839753e12, -0.678686760804270e16, 0.743957464645363e4, -0.356896445355761e20, 0.167590585186801e32, -0.355028625419105e38, @@ -698,8 +698,8 @@ def _h2c3b_s(s: float) -> float: -0.116994334851995e41] suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (sigma-1.02)**i * (sigma-0.726)**j + for i, j, n in zip(I, J, N): + suma += n * (sigma-1.02)**i * (sigma-0.726)**j return 2800*suma**4 @@ -762,7 +762,7 @@ def _Region1(T: float, P: float) -> Dict[str, float]: 4, 4, 5, 8, 8, 21, 23, 29, 30, 31, 32] J = [-2, -1, 0, 1, 2, 3, 4, 5, -9, -7, -1, 0, 1, 3, -3, 0, 1, 3, 17, -4, 0, 6, -5, -2, 10, -8, -11, -6, -29, -31, -38, -39, -40, -41] - n = [0.14632971213167, -0.84548187169114, -0.37563603672040e1, + N = [0.14632971213167, -0.84548187169114, -0.37563603672040e1, 0.33855169168385e1, -0.95791963387872, 0.15772038513228, -0.16616417199501e-1, 0.81214629983568e-3, 0.28319080123804e-3, -0.60706301565874e-3, -0.18990068218419e-1, -0.32529748770505e-1, @@ -777,13 +777,13 @@ def _Region1(T: float, P: float) -> Dict[str, float]: Tr = 1386/T Pr = P/16.53 g = gp = gpp = gt = gtt = gpt = 0.0 - for i, j, ni in zip(I, J, n): - g += ni * (7.1-Pr)**i * (Tr-1.222)**j - gp -= ni*i * (7.1-Pr)**(i-1) * (Tr-1.222)**j - gpp += ni*i*(i-1) * (7.1-Pr)**(i-2) * (Tr-1.222)**j - gt += ni*j * (7.1-Pr)**i * (Tr-1.222)**(j-1) - gtt += ni*j*(j-1) * (7.1-Pr)**i * (Tr-1.222)**(j-2) - gpt -= ni*i*j * (7.1-Pr)**(i-1) * (Tr-1.222)**(j-1) + for i, j, n in zip(I, J, N): + g += n * (7.1-Pr)**i * (Tr-1.222)**j + gp -= n*i * (7.1-Pr)**(i-1) * (Tr-1.222)**j + gpp += n*i*(i-1) * (7.1-Pr)**(i-2) * (Tr-1.222)**j + gt += n*j * (7.1-Pr)**i * (Tr-1.222)**(j-1) + gtt += n*j*(j-1) * (7.1-Pr)**i * (Tr-1.222)**(j-2) + gpt -= n*i*j * (7.1-Pr)**(i-1) * (Tr-1.222)**(j-1) propiedades = {} propiedades["T"] = T @@ -832,7 +832,7 @@ def _Backward1_T_Ph(P: float, h: float) -> float: """ I = [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 3, 4, 5, 6] J = [0, 1, 2, 6, 22, 32, 0, 1, 2, 3, 4, 10, 32, 10, 32, 10, 32, 32, 32, 32] - n = [-0.23872489924521e3, 0.40421188637945e3, 0.11349746881718e3, + N = [-0.23872489924521e3, 0.40421188637945e3, 0.11349746881718e3, -0.58457616048039e1, -0.15285482413140e-3, -0.10866707695377e-5, -0.13391744872602e2, 0.43211039183559e2, -0.54010067170506e2, 0.30535892203916e2, -0.65964749423638e1, 0.93965400878363e-2, @@ -843,8 +843,8 @@ def _Backward1_T_Ph(P: float, h: float) -> float: Pr = P/1 nu = h/2500 T = 0.0 - for i, j, ni in zip(I, J, n): - T += ni * Pr**i * (nu+1)**j + for i, j, n in zip(I, J, N): + T += n * Pr**i * (nu+1)**j return T @@ -878,7 +878,7 @@ def _Backward1_T_Ps(P: float, s: float) -> float: """ I = [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 4] J = [0, 1, 2, 3, 11, 31, 0, 1, 2, 3, 12, 31, 0, 1, 2, 9, 31, 10, 32, 32] - n = [0.17478268058307e3, 0.34806930892873e2, 0.65292584978455e1, + N = [0.17478268058307e3, 0.34806930892873e2, 0.65292584978455e1, 0.33039981775489, -0.19281382923196e-6, -0.24909197244573e-22, -0.26107636489332, 0.22592965981586, -0.64256463395226e-1, 0.78876289270526e-2, 0.35672110607366e-9, 0.17332496994895e-23, @@ -889,8 +889,8 @@ def _Backward1_T_Ps(P: float, s: float) -> float: Pr = P/1 sigma = s/1 T = 0.0 - for i, j, ni in zip(I, J, n): - T += ni * Pr**i * (sigma+2)**j + for i, j, n in zip(I, J, N): + T += n * Pr**i * (sigma+2)**j return T @@ -927,7 +927,7 @@ def _Backward1_P_hs(h: float, s: float) -> float: """ I = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 4, 4, 5] J = [0, 1, 2, 4, 5, 6, 8, 14, 0, 1, 4, 6, 0, 1, 10, 4, 1, 4, 0] - n = [-0.691997014660582, -0.183612548787560e2, -0.928332409297335e1, + N = [-0.691997014660582, -0.183612548787560e2, -0.928332409297335e1, 0.659639569909906e2, -0.162060388912024e2, 0.450620017338667e3, 0.854680678224170e3, 0.607523214001162e4, 0.326487682621856e2, -0.269408844582931e2, -0.319947848334300e3, -0.928354307043320e3, @@ -938,8 +938,8 @@ def _Backward1_P_hs(h: float, s: float) -> float: nu = h/3400 sigma = s/7.6 P = 0.0 - for i, j, ni in zip(I, J, n): - P += ni * (nu+0.05)**i * (sigma+0.05)**j + for i, j, n in zip(I, J, N): + P += n * (nu+0.05)**i * (sigma+0.05)**j return 100*P @@ -1221,7 +1221,7 @@ def _Backward2a_T_Ph(P: float, h: float) -> float: 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7] J = [0, 1, 2, 3, 7, 20, 0, 1, 2, 3, 7, 9, 11, 18, 44, 0, 2, 7, 36, 38, 40, 42, 44, 24, 44, 12, 32, 44, 32, 36, 42, 34, 44, 28] - n = [0.10898952318288e4, 0.84951654495535e3, -0.10781748091826e3, + N = [0.10898952318288e4, 0.84951654495535e3, -0.10781748091826e3, 0.33153654801263e2, -0.74232016790248e1, 0.11765048724356e2, 0.18445749355790e1, -0.41792700549624e1, 0.62478196935812e1, -0.17344563108114e2, -0.20058176862096e3, 0.27196065473796e3, @@ -1237,8 +1237,8 @@ def _Backward2a_T_Ph(P: float, h: float) -> float: Pr = P/1 nu = h/2000 T = 0.0 - for i, j, ni in zip(I, J, n): - T += ni * Pr**i * (nu-2.1)**j + for i, j, n in zip(I, J, N): + T += n * Pr**i * (nu-2.1)**j return T @@ -1274,7 +1274,7 @@ def _Backward2b_T_Ph(P: float, h: float) -> float: 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 6, 7, 7, 9, 9] J = [0, 1, 2, 12, 18, 24, 28, 40, 0, 2, 6, 12, 18, 24, 28, 40, 2, 8, 18, 40, 1, 2, 12, 24, 2, 12, 18, 24, 28, 40, 18, 24, 40, 28, 2, 28, 1, 40] - n = [0.14895041079516e4, 0.74307798314034e3, -0.97708318797837e2, + N = [0.14895041079516e4, 0.74307798314034e3, -0.97708318797837e2, 0.24742464705674e1, -0.63281320016026, 0.11385952129658e1, -0.47811863648625, 0.85208123431544e-2, 0.93747147377932, 0.33593118604916e1, 0.33809355601454e1, 0.16844539671904, @@ -1291,8 +1291,8 @@ def _Backward2b_T_Ph(P: float, h: float) -> float: Pr = P/1 nu = h/2000 T = 0.0 - for i, j, ni in zip(I, J, n): - T += ni * (Pr-2)**i * (nu-2.6)**j + for i, j, n in zip(I, J, N): + T += n * (Pr-2)**i * (nu-2.6)**j return T @@ -1328,7 +1328,7 @@ def _Backward2c_T_Ph(P: float, h: float) -> float: 6, 6, 6] J = [0, 4, 0, 2, 0, 2, 0, 1, 0, 2, 0, 1, 4, 8, 4, 0, 1, 4, 10, 12, 16, 20, 22] - n = [-0.32368398555242e13, 0.73263350902181e13, 0.35825089945447e12, + N = [-0.32368398555242e13, 0.73263350902181e13, 0.35825089945447e12, -0.58340131851590e12, -0.10783068217470e11, 0.20825544563171e11, 0.61074783564516e6, 0.85977722535580e6, -0.25745723604170e5, 0.31081088422714e5, 0.12082315865936e4, 0.48219755109255e3, @@ -1340,8 +1340,8 @@ def _Backward2c_T_Ph(P: float, h: float) -> float: Pr = P/1 nu = h/2000 T = 0.0 - for i, j, ni in zip(I, J, n): - T += ni * (Pr+25)**i * (nu-1.8)**j + for i, j, n in zip(I, J, N): + T += n * (Pr+25)**i * (nu-1.8)**j return T @@ -1412,7 +1412,7 @@ def _Backward2a_T_Ps(P: float, s: float) -> float: J = [-24, -23, -19, -13, -11, -10, -19, -15, -6, -26, -21, -17, -16, -9, -8, -15, -14, -26, -13, -9, -7, -27, -25, -11, -6, 1, 4, 8, 11, 0, 1, 5, 6, 10, 14, 16, 0, 4, 9, 17, 7, 18, 3, 15, 5, 18] - n = [-0.39235983861984e6, 0.51526573827270e6, 0.40482443161048e5, + N = [-0.39235983861984e6, 0.51526573827270e6, 0.40482443161048e5, -0.32193790923902e3, 0.96961424218694e2, -0.22867846371773e2, -0.44942914124357e6, -0.50118336020166e4, 0.35684463560015, 0.44235335848190e5, -0.13673388811708e5, 0.42163260207864e6, @@ -1432,8 +1432,8 @@ def _Backward2a_T_Ps(P: float, s: float) -> float: Pr = P/1 sigma = s/2 T = 0.0 - for i, j, ni in zip(I, J, n): - T += ni * Pr**i * (sigma-2)**j + for i, j, n in zip(I, J, N): + T += n * Pr**i * (sigma-2)**j return T @@ -1470,7 +1470,7 @@ def _Backward2b_T_Ps(P: float, s: float) -> float: 4, 4, 5, 5, 5] J = [0, 11, 0, 11, 0, 1, 11, 0, 1, 11, 12, 0, 1, 6, 10, 0, 1, 5, 8, 9, 0, 1, 2, 4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 0, 1, 5, 0, 1, 3, 0, 1, 0, 1, 2] - n = [0.31687665083497e6, 0.20864175881858e2, -0.39859399803599e6, + N = [0.31687665083497e6, 0.20864175881858e2, -0.39859399803599e6, -0.21816058518877e2, 0.22369785194242e6, -0.27841703445817e4, 0.99207436071480e1, -0.75197512299157e5, 0.29708605951158e4, -0.34406878548526e1, 0.38815564249115, 0.17511295085750e5, @@ -1489,8 +1489,8 @@ def _Backward2b_T_Ps(P: float, s: float) -> float: Pr = P/1 sigma = s/0.7853 T = 0.0 - for i, j, ni in zip(I, J, n): - T += ni * Pr**i * (10-sigma)**j + for i, j, n in zip(I, J, N): + T += n * Pr**i * (10-sigma)**j return T @@ -1526,7 +1526,7 @@ def _Backward2c_T_Ps(P: float, s: float) -> float: 5, 6, 6, 7, 7, 7, 7, 7] J = [0, 1, 0, 0, 1, 2, 3, 0, 1, 3, 4, 0, 1, 2, 0, 1, 5, 0, 1, 4, 0, 1, 2, 0, 1, 0, 1, 3, 4, 5] - n = [0.90968501005365e3, 0.24045667088420e4, -0.59162326387130e3, + N = [0.90968501005365e3, 0.24045667088420e4, -0.59162326387130e3, 0.54145404128074e3, -0.27098308411192e3, 0.97976525097926e3, -0.46966772959435e3, 0.14399274604723e2, -0.19104204230429e2, 0.53299167111971e1, -0.21252975375934e2, -0.31147334413760, @@ -1540,8 +1540,8 @@ def _Backward2c_T_Ps(P: float, s: float) -> float: Pr = P/1 sigma = s/2.9251 T = 0.0 - for i, j, ni in zip(I, J, n): - T += ni * Pr**i * (2-sigma)**j + for i, j, n in zip(I, J, N): + T += n * Pr**i * (2-sigma)**j return T @@ -1608,7 +1608,7 @@ def _Backward2a_P_hs(h: float, s: float) -> float: 3, 4, 5, 5, 6, 7] J = [1, 3, 6, 16, 20, 22, 0, 1, 2, 3, 5, 6, 10, 16, 20, 22, 3, 16, 20, 0, 2, 3, 6, 16, 16, 3, 16, 3, 1] - n = [-0.182575361923032e-1, -0.125229548799536, 0.592290437320145, + N = [-0.182575361923032e-1, -0.125229548799536, 0.592290437320145, 0.604769706185122e1, 0.238624965444474e3, -0.298639090222922e3, 0.512250813040750e-1, -0.437266515606486, 0.413336902999504, -0.516468254574773e1, -0.557014838445711e1, 0.128555037824478e2, @@ -1622,8 +1622,8 @@ def _Backward2a_P_hs(h: float, s: float) -> float: nu = h/4200 sigma = s/12 suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (nu-0.5)**i * (sigma-1.2)**j + for i, j, n in zip(I, J, N): + suma += n * (nu-0.5)**i * (sigma-1.2)**j return 4*suma**4 @@ -1662,7 +1662,7 @@ def _Backward2b_P_hs(h: float, s: float) -> float: 6, 6, 7, 7, 8, 8, 8, 8, 12, 14] J = [0, 1, 2, 4, 8, 0, 1, 2, 3, 5, 12, 1, 6, 18, 0, 1, 7, 12, 1, 16, 1, 12, 1, 8, 18, 1, 16, 1, 3, 14, 18, 10, 16] - n = [0.801496989929495e-1, -0.543862807146111, 0.337455597421283, + N = [0.801496989929495e-1, -0.543862807146111, 0.337455597421283, 0.890555451157450e1, 0.313840736431485e3, 0.797367065977789, -0.121616973556240e1, 0.872803386937477e1, -0.169769781757602e2, -0.186552827328416e3, 0.951159274344237e5, -0.189168510120494e2, @@ -1677,8 +1677,8 @@ def _Backward2b_P_hs(h: float, s: float) -> float: nu = h/4100 sigma = s/7.9 suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (nu-0.6)**i * (sigma-1.01)**j + for i, j, n in zip(I, J, N): + suma += n * (nu-0.6)**i * (sigma-1.01)**j return 100*suma**4 @@ -1717,7 +1717,7 @@ def _Backward2c_P_hs(h: float, s: float) -> float: 5, 5, 5, 6, 6, 10, 12, 16] J = [0, 1, 2, 3, 4, 8, 0, 2, 5, 8, 14, 2, 3, 7, 10, 18, 0, 5, 8, 16, 18, 18, 1, 4, 6, 14, 8, 18, 7, 7, 10] - n = [0.112225607199012, -0.339005953606712e1, -0.320503911730094e2, + N = [0.112225607199012, -0.339005953606712e1, -0.320503911730094e2, -0.197597305104900e3, -0.407693861553446e3, 0.132943775222331e5, 0.170846839774007e1, 0.373694198142245e2, 0.358144365815434e4, 0.423014446424664e6, -0.751071025760063e9, 0.523446127607898e2, @@ -1732,8 +1732,8 @@ def _Backward2c_P_hs(h: float, s: float) -> float: nu = h/3500 sigma = s/5.9 suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (nu-0.7)**i * (sigma-1.1)**j + for i, j, n in zip(I, J, N): + suma += n * (nu-0.7)**i * (sigma-1.1)**j return 100*suma**4 @@ -1820,7 +1820,7 @@ def _Region3(rho: float, T: float) -> Dict[str, float]: 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 8, 9, 9, 10, 10, 11] J = [0, 1, 2, 7, 10, 12, 23, 2, 6, 15, 17, 0, 2, 6, 7, 22, 26, 0, 2, 4, 16, 26, 0, 2, 4, 26, 1, 3, 26, 0, 2, 26, 2, 26, 2, 26, 0, 1, 26] - n = [-0.15732845290239e2, 0.20944396974307e2, -0.76867707878716e1, + N = [-0.15732845290239e2, 0.20944396974307e2, -0.76867707878716e1, 0.26185947787954e1, -0.28080781148620e1, 0.12053369696517e1, -0.84566812812502e-2, -0.12654315477714e1, -0.11524407806681e1, 0.88521043984318, -0.64207765181607, 0.38493460186671, @@ -1840,13 +1840,13 @@ def _Region3(rho: float, T: float) -> Dict[str, float]: gd = 1.0658070028513/d gdd = -1.0658070028513/d**2 gt = gtt = gdt = 0.0 - for i, j, ni in zip(I, J, n): - g += ni * d**i * Tr**j - gd += ni*i * d**(i-1) * Tr**j - gdd += ni*i*(i-1) * d**(i-2) * Tr**j - gt += ni*j * d**i * Tr**(j-1) - gtt += ni*j*(j-1) * d**i * Tr**(j-2) - gdt += ni*i*j * d**(i-1) * Tr**(j-1) + for i, j, n in zip(I, J, N): + g += n * d**i * Tr**j + gd += n*i * d**(i-1) * Tr**j + gdd += n*i*(i-1) * d**(i-2) * Tr**j + gt += n*j * d**i * Tr**(j-1) + gtt += n*j*(j-1) * d**i * Tr**(j-2) + gdt += n*i*j * d**(i-1) * Tr**(j-1) propiedades = {} propiedades["T"] = T @@ -1913,13 +1913,13 @@ def _tab_P(P: float) -> float: 693.0341408 """ I = [0, 1, 2, -1, -2] - n = [0.154793642129415e4, -0.187661219490113e3, 0.213144632222113e2, + N = [0.154793642129415e4, -0.187661219490113e3, 0.213144632222113e2, -0.191887498864292e4, 0.918419702359447e3] Pr = P/1 T = 0.0 - for i, ni in zip(I, n): - T += ni * log(Pr)**i + for i, n in zip(I, N): + T += n * log(Pr)**i return T @@ -1949,13 +1949,13 @@ def _top_P(P: float) -> float: 650.0106943 """ I = [0, 1, 2, -1, -2] - n = [0.969461372400213e3, -0.332500170441278e3, 0.642859598466067e2, + N = [0.969461372400213e3, -0.332500170441278e3, 0.642859598466067e2, 0.773845935768222e3, -0.152313732937084e4] Pr = P/1 T = 0.0 - for i, ni in zip(I, n): - T += ni * log(Pr)**i + for i, n in zip(I, N): + T += n * log(Pr)**i return T @@ -1985,13 +1985,13 @@ def _twx_P(P: float) -> float: 648.2049480 """ I = [0, 1, 2, -1, -2] - n = [0.728052609145380e1, 0.973505869861952e2, 0.147370491183191e2, + N = [0.728052609145380e1, 0.973505869861952e2, 0.147370491183191e2, 0.329196213998375e3, 0.873371668682417e3] Pr = P/1 T = 0.0 - for i, ni in zip(I, n): - T += ni * log(Pr)**i + for i, n in zip(I, N): + T += n * log(Pr)**i return T @@ -2064,7 +2064,7 @@ def _txx_P(P: float, xy: str) -> float: >>> _txx_P(22.3,"uv") 647.7996121 """ - ng = { + N = { "cd": [0.585276966696349e3, 0.278233532206915e1, -0.127283549295878e-1, 0.159090746562729e-3], "gh": [-0.249284240900418e5, 0.428143584791546e4, -0.269029173140130e3, @@ -2082,11 +2082,10 @@ def _txx_P(P: float, xy: str) -> float: "uv": [0.528199646263062e3, 0.890579602135307e1, -0.222814134903755, 0.286791682263697e-2]} - n = ng[xy] Pr = P/1 T = 0.0 - for i, ni in enumerate(n): - T += ni * Pr**i + for i, n in enumerate(N[xy]): + T += n * Pr**i return T @@ -2123,7 +2122,7 @@ def _Backward3a_v_Ph(P: float, h: float) -> float: -2, -1, -1, -1, -1, 0, 0, 1, 1, 1, 2, 2, 3, 4, 5, 8] J = [6, 8, 12, 18, 4, 7, 10, 5, 12, 3, 4, 22, 2, 3, 7, 3, 16, 0, 1, 2, 3, 0, 1, 0, 1, 2, 0, 2, 0, 2, 2, 2] - n = [0.529944062966028e-2, -0.170099690234461, 0.111323814312927e2, + N = [0.529944062966028e-2, -0.170099690234461, 0.111323814312927e2, -0.217898123145125e4, -0.506061827980875e-3, 0.556495239685324, -0.943672726094016e1, -0.297856807561527, 0.939353943717186e2, 0.192944939465981e-1, 0.421740664704763, -0.368914126282330e7, @@ -2138,8 +2137,8 @@ def _Backward3a_v_Ph(P: float, h: float) -> float: Pr = P/100 nu = h/2100 suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (Pr+0.128)**i * (nu-0.727)**j + for i, j, n in zip(I, J, N): + suma += n * (Pr+0.128)**i * (nu-0.727)**j return 0.0028*suma @@ -2176,7 +2175,7 @@ def _Backward3b_v_Ph(P: float, h: float) -> float: -3, -3, -2, -2, -1, -1, -1, -1, 0, 1, 1, 2, 2] J = [0, 1, 0, 1, 3, 6, 7, 8, 0, 1, 2, 5, 6, 10, 3, 6, 10, 0, 2, 1, 2, 0, 1, 4, 5, 0, 0, 1, 2, 6] - n = [-0.225196934336318e-8, 0.140674363313486e-7, 0.233784085280560e-5, + N = [-0.225196934336318e-8, 0.140674363313486e-7, 0.233784085280560e-5, -0.331833715229001e-4, 0.107956778514318e-2, -0.271382067378863, 0.107202262490333e1, -0.853821329075382, -0.215214194340526e-4, 0.769656088222730e-3, -0.431136580433864e-2, 0.453342167309331, @@ -2190,8 +2189,8 @@ def _Backward3b_v_Ph(P: float, h: float) -> float: Pr = P/100 nu = h/2800 suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (Pr+0.0661)**i * (nu-0.72)**j + for i, j, n in zip(I, J, N): + suma += n * (Pr+0.0661)**i * (nu-0.72)**j return 0.0088*suma @@ -2303,7 +2302,7 @@ def _Backward3b_T_Ph(P: float, h: float) -> float: -4, -3, -2, -2, -1, -1, -1, -1, -1, -1, 0, 0, 1, 3, 5, 6, 8] J = [0, 1, 0, 1, 5, 10, 12, 0, 1, 2, 4, 10, 0, 1, 2, 0, 1, 5, 0, 4, 2, 4, 6, 10, 14, 16, 0, 2, 1, 1, 1, 1, 1] - n = [0.323254573644920e-4, -0.127575556587181e-3, -0.475851877356068e-3, + N = [0.323254573644920e-4, -0.127575556587181e-3, -0.475851877356068e-3, 0.156183014181602e-2, 0.105724860113781, -0.858514221132534e2, 0.724140095480911e3, 0.296475810273257e-2, -0.592721983365988e-2, -0.126305422818666e-1, -0.115716196364853, 0.849000969739595e2, @@ -2318,7 +2317,7 @@ def _Backward3b_T_Ph(P: float, h: float) -> float: Pr = P/100. nu = h/2800. suma = 0.0 - for i, j, n in zip(I, J, n): + for i, j, n in zip(I, J, N): suma += n*(Pr+0.298)**i*(nu-0.72)**j return 860*suma @@ -2379,7 +2378,7 @@ def _Backward3a_v_Ps(P: float, s: float) -> float: -2, -2, -1, -1, 0, 0, 0, 1, 2, 4, 5, 6] J = [10, 12, 14, 4, 8, 10, 20, 5, 6, 14, 16, 28, 1, 5, 2, 4, 3, 8, 1, 2, 0, 1, 3, 0, 0, 2, 2, 0] - n = [0.795544074093975e2, -0.238261242984590e4, 0.176813100617787e5, + N = [0.795544074093975e2, -0.238261242984590e4, 0.176813100617787e5, -0.110524727080379e-2, -0.153213833655326e2, 0.297544599376982e3, -0.350315206871242e8, 0.277513761062119, -0.523964271036888, -0.148011182995403e6, 0.160014899374266e7, 0.170802322663427e13, @@ -2393,8 +2392,8 @@ def _Backward3a_v_Ps(P: float, s: float) -> float: Pr = P/100 sigma = s/4.4 suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (Pr+0.187)**i * (sigma-0.755)**j + for i, j, n in zip(I, J, N): + suma += n * (Pr+0.187)**i * (sigma-0.755)**j return 0.0028*suma @@ -2431,7 +2430,7 @@ def _Backward3b_v_Ps(P: float, s: float) -> float: -4, -4, -4, -3, -2, -2, -2, -2, -2, -2, 0, 0, 0, 1, 1, 2] J = [0, 1, 2, 3, 5, 6, 0, 1, 2, 4, 0, 1, 2, 3, 0, 1, 2, 3, 1, 0, 1, 2, 3, 4, 12, 0, 1, 2, 0, 2, 2] - n = [0.591599780322238e-4, -0.185465997137856e-2, 0.104190510480013e-1, + N = [0.591599780322238e-4, -0.185465997137856e-2, 0.104190510480013e-1, 0.598647302038590e-2, -0.771391189901699, 0.172549765557036e1, -0.467076079846526e-3, 0.134533823384439e-1, -0.808094336805495e-1, 0.508139374365767, 0.128584643361683e-2, -0.163899353915435e1, @@ -2446,8 +2445,8 @@ def _Backward3b_v_Ps(P: float, s: float) -> float: Pr = P/100 sigma = s/5.3 suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (Pr+0.298)**i * (sigma-0.816)**j + for i, j, n in zip(I, J, N): + suma += n * (Pr+0.298)**i * (sigma-0.816)**j return 0.0088*suma @@ -2505,7 +2504,7 @@ def _Backward3a_T_Ps(P: float, s: float) -> float: -4, -4, -4, -2, -2, -1, -1, 0, 0, 0, 1, 2, 2, 3, 8, 8, 10] J = [28, 32, 4, 10, 12, 14, 5, 7, 8, 28, 2, 6, 32, 0, 14, 32, 6, 10, 36, 1, 4, 1, 6, 0, 1, 4, 0, 0, 3, 2, 0, 1, 2] - n = [0.150042008263875e10, -0.159397258480424e12, 0.502181140217975e-3, + N = [0.150042008263875e10, -0.159397258480424e12, 0.502181140217975e-3, -0.672057767855466e2, 0.145058545404456e4, -0.823889534888890e4, -0.154852214233853, 0.112305046746695e2, -0.297000213482822e2, 0.438565132635495e11, 0.137837838635464e-2, -0.297478527157462e1, @@ -2520,8 +2519,8 @@ def _Backward3a_T_Ps(P: float, s: float) -> float: Pr = P/100 sigma = s/4.4 suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (Pr+0.240)**i * (sigma-0.703)**j + for i, j, n in zip(I, J, N): + suma += n * (Pr+0.240)**i * (sigma-0.703)**j return 760*suma @@ -2558,7 +2557,7 @@ def _Backward3b_T_Ps(P: float, s: float) -> float: -3, -3, -2, 0, 2, 3, 4, 5, 6, 8, 12, 14] J = [1, 3, 4, 7, 0, 1, 3, 0, 2, 4, 0, 1, 2, 4, 6, 12, 1, 6, 2, 0, 1, 1, 0, 24, 0, 3, 1, 2] - n = [0.527111701601660, -0.401317830052742e2, 0.153020073134484e3, + N = [0.527111701601660, -0.401317830052742e2, 0.153020073134484e3, -0.224799398218827e4, -0.193993484669048, -0.140467557893768e1, 0.426799878114024e2, 0.752810643416743, 0.226657238616417e2, -0.622873556909932e3, -0.660823667935396, 0.841267087271658, @@ -2572,8 +2571,8 @@ def _Backward3b_T_Ps(P: float, s: float) -> float: Pr = P/100 sigma = s/5.3 suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (Pr+0.760)**i * (sigma-0.818)**j + for i, j, n in zip(I, J, N): + suma += n * (Pr+0.760)**i * (sigma-0.818)**j return 860*suma @@ -2636,7 +2635,7 @@ def _Backward3a_P_hs(h: float, s: float) -> float: 14, 18, 20, 22, 22, 24, 28, 28, 32, 32] J = [0, 1, 5, 0, 3, 4, 8, 14, 6, 16, 0, 2, 3, 0, 1, 4, 5, 28, 28, 24, 1, 32, 36, 22, 28, 36, 16, 28, 36, 16, 36, 10, 28] - n = [0.770889828326934e1, -0.260835009128688e2, 0.267416218930389e3, + N = [0.770889828326934e1, -0.260835009128688e2, 0.267416218930389e3, 0.172221089496844e2, -0.293542332145970e3, 0.614135601882478e3, -0.610562757725674e5, -0.651272251118219e8, 0.735919313521937e5, -0.116646505914191e11, 0.355267086434461e2, -0.596144543825955e3, @@ -2651,8 +2650,8 @@ def _Backward3a_P_hs(h: float, s: float) -> float: nu = h/2300 sigma = s/4.4 suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (nu-1.01)**i * (sigma-0.75)**j + for i, j, n in zip(I, J, N): + suma += n * (nu-1.01)**i * (sigma-0.75)**j return 99*suma @@ -2693,7 +2692,7 @@ def _Backward3b_P_hs(h: float, s: float) -> float: 14] J = [2, 10, 12, 14, 20, 2, 10, 14, 18, 2, 8, 2, 6, 7, 8, 10, 4, 5, 8, 1, 3, 5, 6, 0, 1, 0, 3, 0, 1, 0, 1, 1, 1, 3, 7] - n = [0.125244360717979e-12, -0.126599322553713e-1, 0.506878030140626e1, + N = [0.125244360717979e-12, -0.126599322553713e-1, 0.506878030140626e1, 0.317847171154202e2, -0.391041161399932e6, -0.975733406392044e-10, -0.186312419488279e2, 0.510973543414101e3, 0.373847005822362e6, 0.299804024666572e-7, 0.200544393820342e2, -0.498030487662829e-5, @@ -2709,8 +2708,8 @@ def _Backward3b_P_hs(h: float, s: float) -> float: nu = h/2800 sigma = s/5.3 suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (nu-0.681)**i * (sigma-0.792)**j + for i, j, n in zip(I, J, N): + suma += n * (nu-0.681)**i * (sigma-0.792)**j return 16.6/suma @@ -3248,7 +3247,7 @@ def _Backward3x_v_PT(T: float, P: float, x: str) -> float: "z": [3, 6, 6, 8, 5, 6, 8, -2, 5, 6, 2, -6, 3, 1, 6, -6, -2, -6, -5, -4, -1, -8, -4]} - n = { + N = { "a": [0.110879558823853e-2, 0.572616740810616e3, -0.767051948380852e5, -0.253321069529674e-1, 0.628008049345689e4, 0.234105654131876e6, 0.216867826045856, -0.156237904341963e3, -0.269893956176613e5, @@ -3551,21 +3550,18 @@ def _Backward3x_v_PT(T: float, P: float, x: str) -> float: 0.154355721681459e2, -0.373962862928643e4, -0.682859011374572e11, -0.248488015614543e-3, 0.394536049497068e7]} - I = I[x] - J = J[x] - n = n[x] v_, P_, T_, a, b, c, d, e = par[x] Pr = P/P_ Tr = T/T_ suma = 0.0 if x == "n": - for i, j, ni in zip(I, J, n): - suma += ni * (Pr-a)**i * (Tr-b)**j + for i, j, n in zip(I[x], J[x], N[x]): + suma += n * (Pr-a)**i * (Tr-b)**j return v_*exp(suma) else: - for i, j, ni in zip(I, J, n): - suma += ni * (Pr-a)**(c*i) * (Tr-b)**(j*d) + for i, j, n in zip(I[x], J[x], N[x]): + suma += n * (Pr-a)**(c*i) * (Tr-b)**(j*d) return v_*suma**e @@ -3654,7 +3650,7 @@ def _Backward4_T_hs(h: float, s: float) -> float: 8, 10, 10, 12, 14, 14, 16, 16, 18, 18, 18, 20, 28] J = [0, 3, 12, 0, 1, 2, 5, 0, 5, 8, 0, 2, 3, 4, 0, 1, 1, 2, 4, 16, 6, 8, 22, 1, 20, 36, 24, 1, 28, 12, 32, 14, 22, 36, 24, 36] - n = [0.179882673606601, -0.267507455199603, 0.116276722612600e1, + N = [0.179882673606601, -0.267507455199603, 0.116276722612600e1, 0.147545428713616, -0.512871635973248, 0.421333567697984, 0.563749522189870, 0.429274443819153, -0.335704552142140e1, 0.108890916499278e2, -0.248483390456012, 0.304153221906390, @@ -3670,8 +3666,8 @@ def _Backward4_T_hs(h: float, s: float) -> float: nu = h/2800 sigma = s/9.2 suma = 0.0 - for i, j, ni in zip(I, J, n): - suma += ni * (nu-0.119)**i * (sigma-1.07)**j + for i, j, n in zip(I, J, N): + suma += n * (nu-0.119)**i * (sigma-1.07)**j return 550*suma From 59b3faf570113bd813c76f4a17a9fd0ba8697303 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sun, 14 Mar 2021 19:15:47 -0400 Subject: [PATCH 041/102] Resolve type ambiguity ir par[]. This approach also made it clearer (to me at least) what was actually special about case 'n'. --- iapws/iapws97.py | 60 +++++++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/iapws/iapws97.py b/iapws/iapws97.py index bb6976e..12e064b 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -3092,32 +3092,32 @@ def _Backward3x_v_PT(T: float, P: float, x: str) -> float: 0.003701940009 """ par = { - "a": [0.0024, 100, 760, 0.085, 0.817, 1, 1, 1], - "b": [0.0041, 100, 860, 0.280, 0.779, 1, 1, 1], - "c": [0.0022, 40, 690, 0.259, 0.903, 1, 1, 1], - "d": [0.0029, 40, 690, 0.559, 0.939, 1, 1, 4], - "e": [0.0032, 40, 710, 0.587, 0.918, 1, 1, 1], - "f": [0.0064, 40, 730, 0.587, 0.891, 0.5, 1, 4], - "g": [0.0027, 25, 660, 0.872, 0.971, 1, 1, 4], - "h": [0.0032, 25, 660, 0.898, 0.983, 1, 1, 4], - "i": [0.0041, 25, 660, 0.910, 0.984, 0.5, 1, 4], - "j": [0.0054, 25, 670, 0.875, 0.964, 0.5, 1, 4], - "k": [0.0077, 25, 680, 0.802, 0.935, 1, 1, 1], - "l": [0.0026, 24, 650, 0.908, 0.989, 1, 1, 4], - "m": [0.0028, 23, 650, 1.000, 0.997, 1, 0.25, 1], - "n": [0.0031, 23, 650, 0.976, 0.997, None, None, None], - "o": [0.0034, 23, 650, 0.974, 0.996, 0.5, 1, 1], - "p": [0.0041, 23, 650, 0.972, 0.997, 0.5, 1, 1], - "q": [0.0022, 23, 650, 0.848, 0.983, 1, 1, 4], - "r": [0.0054, 23, 650, 0.874, 0.982, 1, 1, 1], - "s": [0.0022, 21, 640, 0.886, 0.990, 1, 1, 4], - "t": [0.0088, 20, 650, 0.803, 1.020, 1, 1, 1], - "u": [0.0026, 23, 650, 0.902, 0.988, 1, 1, 1], - "v": [0.0031, 23, 650, 0.960, 0.995, 1, 1, 1], - "w": [0.0039, 23, 650, 0.959, 0.995, 1, 1, 4], - "x": [0.0049, 23, 650, 0.910, 0.988, 1, 1, 1], - "y": [0.0031, 22, 650, 0.996, 0.994, 1, 1, 4], - "z": [0.0038, 22, 650, 0.993, 0.994, 1, 1, 4], + "a": [0.0024, 100, 760, 0.085, 0.817, 1.0, 1.0, 1.0], + "b": [0.0041, 100, 860, 0.280, 0.779, 1.0, 1.0, 1.0], + "c": [0.0022, 40, 690, 0.259, 0.903, 1.0, 1.0, 1.0], + "d": [0.0029, 40, 690, 0.559, 0.939, 1.0, 1.0, 4.0], + "e": [0.0032, 40, 710, 0.587, 0.918, 1.0, 1.0, 1.0], + "f": [0.0064, 40, 730, 0.587, 0.891, 0.5, 1.0, 4.0], + "g": [0.0027, 25, 660, 0.872, 0.971, 1.0, 1.0, 4.0], + "h": [0.0032, 25, 660, 0.898, 0.983, 1.0, 1.0, 4.0], + "i": [0.0041, 25, 660, 0.910, 0.984, 0.5, 1.0, 4.0], + "j": [0.0054, 25, 670, 0.875, 0.964, 0.5, 1.0, 4.0], + "k": [0.0077, 25, 680, 0.802, 0.935, 1.0, 1.0, 1.0], + "l": [0.0026, 24, 650, 0.908, 0.989, 1.0, 1.0, 4.0], + "m": [0.0028, 23, 650, 1.000, 0.997, 1.0, 0.25, 1.0], + "n": [0.0031, 23, 650, 0.976, 0.997, 1.0, 1.0, 1.0], + "o": [0.0034, 23, 650, 0.974, 0.996, 0.5, 1.0, 1.0], + "p": [0.0041, 23, 650, 0.972, 0.997, 0.5, 1.0, 1.0], + "q": [0.0022, 23, 650, 0.848, 0.983, 1.0, 1.0, 4.0], + "r": [0.0054, 23, 650, 0.874, 0.982, 1.0, 1.0, 1.0], + "s": [0.0022, 21, 640, 0.886, 0.990, 1.0, 1.0, 4.0], + "t": [0.0088, 20, 650, 0.803, 1.020, 1.0, 1.0, 1.0], + "u": [0.0026, 23, 650, 0.902, 0.988, 1.0, 1.0, 1.0], + "v": [0.0031, 23, 650, 0.960, 0.995, 1.0, 1.0, 1.0], + "w": [0.0039, 23, 650, 0.959, 0.995, 1.0, 1.0, 4.0], + "x": [0.0049, 23, 650, 0.910, 0.988, 1.0, 1.0, 1.0], + "y": [0.0031, 22, 650, 0.996, 0.994, 1.0, 1.0, 4.0], + "z": [0.0038, 22, 650, 0.993, 0.994, 1.0, 1.0, 4.0], } I = { @@ -3555,13 +3555,11 @@ def _Backward3x_v_PT(T: float, P: float, x: str) -> float: Pr = P/P_ Tr = T/T_ suma = 0.0 - if x == "n": - for i, j, n in zip(I[x], J[x], N[x]): - suma += n * (Pr-a)**i * (Tr-b)**j + for i, j, n in zip(I[x], J[x], N[x]): + suma += n * (Pr-a)**(c*i) * (Tr-b)**(j*d) + if x == 'n': return v_*exp(suma) else: - for i, j, n in zip(I[x], J[x], N[x]): - suma += n * (Pr-a)**(c*i) * (Tr-b)**(j*d) return v_*suma**e From 236f0eee91c7b00b36f308f3f7700716b38a5d3b Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sun, 14 Mar 2021 20:00:03 -0400 Subject: [PATCH 042/102] Clear up some typing issues surrounding _Pv, _rhoL and _rhoG. Mostly these changes were about making it easier for mypy to detect the types of the float lists, but it also made the relatonship between the base class and the derived classes a lot clearer. I think the design would be cleaner with a base class implementation that took constants as parameters from short stubs in the derived classes. --- iapws/ammonia.py | 21 +++++------ iapws/humidAir.py | 16 ++++---- iapws/iapws95.py | 94 ++++++++++++++++++++++++++--------------------- 3 files changed, 70 insertions(+), 61 deletions(-) diff --git a/iapws/ammonia.py b/iapws/ammonia.py index 4ed7102..dce9282 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -74,18 +74,15 @@ class NH3(MEoS): "a3": [0.2533125e4], "exp3": [1]} _surf = {"sigma": [0.1028, -0.09453], "exp": [1.211, 5.585]} - _Pv = { - "eq": 5, - "ao": [-0.70993e1, -0.24330e1, 0.87591e1, -0.64091e1, -0.21185e1], - "exp": [1., 1.5, 1.7, 1.95, 4.2]} - _rhoL = { - "eq": 1, - "ao": [0.34488e2, -0.12849e3, 0.17382e3, -0.10699e3, 0.30339e2], - "exp": [0.58, 0.75, 0.9, 1.1, 1.3]} - _rhoG = { - "eq": 3, - "ao": [-.38435, -4.0846, -6.6634, -0.31881e2, 0.21306e3, -0.24648e3], - "exp": [0.218, 0.55, 1.5, 3.7, 5.5, 5.8]} + # _Pv_eq = 5 # unused + _Pv_ao = [-0.70993e1, -0.24330e1, 0.87591e1, -0.64091e1, -0.21185e1] + _Pv_exp = [1.0, 1.5, 1.7, 1.95, 4.2] + _rhoL_eq = 1 + _rhoL_ao = [0.34488e2, -0.12849e3, 0.17382e3, -0.10699e3, 0.30339e2] + _rhoL_exp = [0.58, 0.75, 0.9, 1.1, 1.3] + _rhoG_eq = 3 + _rhoG_ao = [-.38435, -4.0846, -6.6634, -0.31881e2, 0.21306e3, -0.24648e3] + _rhoG_exp = [0.218, 0.55, 1.5, 3.7, 5.5, 5.8] def _visco(self, rho: float, T: float, fase=None) -> Optional[float]: """Equation for the Viscosity diff --git a/iapws/humidAir.py b/iapws/humidAir.py index 67a2916..0529f02 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -329,13 +329,15 @@ class Air(MEoSBlend): "exp1": [0, 0.178963e1, 0], "a2": [], "exp2": [], "a3": [], "exp3": []} _surf = {"sigma": [0.03046], "exp": [1.28]} - _rhoG = { - "eq": 3, - "ao": [-0.20466e1, -0.4752e1, -0.13259e2, -0.47652e2], - "exp": [0.41, 1, 2.8, 6.5]} - _Pv = { - "ao": [-0.1567266, -0.5539635e1, 0.7567212, -0.3514322e1], - "exp": [0.5, 1, 2.5, 4]} + _Pv_ao = [-0.1567266, -0.5539635e1, 0.7567212, -0.3514322e1] + _Pv_exp = [0.5, 1.0, 2.5, 4.0] + # No rhoL equation for humidAir because _Liquid_Density() is overridden instead. + _rhoL_eq = 0 + _rhoL_ao = [0.0] + _rhoL_exp = [0.0] + _rhoG_eq = 3 + _rhoG_ao = [-0.20466e1, -0.4752e1, -0.13259e2, -0.47652e2] + _rhoG_exp = [0.41, 1.0, 2.8, 6.5] @classmethod def _Liquid_Density(cls, T: float) -> float: diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 5badb71..4dce205 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -17,7 +17,7 @@ from numpy import exp, log, ndarray from scipy.optimize import fsolve -from typing import Tuple, Dict, Optional, Union, List +from typing import Tuple, Dict, Optional, List from .iapws97 import _TSat_P, IAPWS97 from ._iapws import M, Tc, Pc, rhoc, Tc_D2O, Pc_D2O, rhoc_D2O @@ -371,9 +371,17 @@ class MEoS(_fase): """ CP = None - _Pv: Optional[Dict[str, Union[int, List[float]]]] = None - _rhoL: Optional[Dict[str, Union[int, List[float]]]] = None - _rhoG: Optional[Dict[str, Union[int, List[float]]]] = None + # The lists vary from 4 to 6 terms, which is why they're not + # tuples of explicit length. The equation numbers are used for + # switching implementations based on class. + _Pv_ao: List[float] + _Pv_exp: List[float] + _rhoG_eq: int + _rhoG_ao: List[float] + _rhoG_exp: List[float] + _rhoL_eq: int + _rhoL_ao: List[float] + _rhoL_exp: List[float] kwargs = {"T": 0.0, "P": 0.0, @@ -401,6 +409,16 @@ class MEoS(_fase): def __init__(self, **kwargs): """Constructor, define common constant and initinialice kwargs""" + # These class variables must be defined by the subclass. + assert(isinstance(self._Pv_ao, list)) + assert(isinstance(self._Pv_exp, list)) + assert(isinstance(self._rhoL_eq, int)) + assert(isinstance(self._rhoL_ao, list)) + assert(isinstance(self._rhoL_exp, list)) + assert(isinstance(self._rhoG_eq, int)) + assert(isinstance(self._rhoG_ao, list)) + assert(isinstance(self._rhoG_exp, list)) + self.R = self._constants["R"][0]/self._constants.get("M", self.M) self.Zc = self.Pc/self.rhoc/self.R/self.Tc self.kwargs = MEoS.kwargs.copy() @@ -2109,7 +2127,7 @@ def _Vapor_Pressure(cls, T: float) -> float: """ Tita = 1-T/cls.Tc suma = 0.0 - for n, x in zip(cls._Pv["ao"], cls._Pv["exp"]): + for n, x in zip(cls._Pv_ao, cls._Pv_exp): suma += n*Tita**x Pr = exp(cls.Tc/T*suma) Pv = Pr*cls.Pc @@ -2135,12 +2153,11 @@ def _Liquid_Density(cls, T: float) -> float: Ordinary Water Substance September 1992, http://www.iapws.org/relguide/Supp-sat.html, Eq.2 """ - eq = cls._rhoL["eq"] Tita = 1-T/cls.Tc - if eq == 2: + if cls._rhoL_eq == 2: Tita = Tita**(1./3) - suma = 0 - for n, x in zip(cls._rhoL["ao"], cls._rhoL["exp"]): + suma = 0.0 + for n, x in zip(cls._rhoL_ao, cls._rhoL_exp): suma += n*Tita**x Pr = suma+1 rho = Pr*cls.rhoc @@ -2166,12 +2183,11 @@ def _Vapor_Density(cls, T: float) -> float: Ordinary Water Substance September 1992, http://www.iapws.org/relguide/Supp-sat.html, Eq.3 """ - eq = cls._rhoG["eq"] Tita = 1-T/cls.Tc - if eq == 4: + if cls._rhoG_eq == 4: Tita = Tita**(1./3) - suma = 0 - for n, x in zip(cls._rhoG["ao"], cls._rhoG["exp"]): + suma = 0.0 + for n, x in zip(cls._rhoG_ao, cls._rhoG_exp): suma += n*Tita**x Pr = exp(suma) rho = Pr*cls.rhoc @@ -2198,9 +2214,9 @@ def _dPdT_sat(cls, T: float) -> float: http://www.iapws.org/relguide/Supp-sat.html, derived from Eq.1 """ Tita = 1-T/cls.Tc - suma1 = 0 - suma2 = 0 - for n, x in zip(cls._Pv["ao"], cls._Pv["exp"]): + suma1 = 0.0 + suma2 = 0.0 + for n, x in zip(cls._Pv_ao, cls._Pv_exp): suma1 -= n*x*Tita**(x-1)/cls.Tc suma2 += n*Tita**x Pr = (cls.Tc*suma1/T-cls.Tc/T**2*suma2)*exp(cls.Tc/T*suma2) @@ -2418,20 +2434,17 @@ class IAPWS95(MEoS): "A": [0.32, .32], "beta4": [0.3, 0.3]} - _Pv = { - "ao": [-7.85951783, 1.84408259, -11.7866497, 22.6807411, -15.9618719, - 1.80122502], - "exp": [1, 1.5, 3, 3.5, 4, 7.5]} - _rhoL = { - "eq": 2, - "ao": [1.99274064, 1.09965342, -0.510839303, -1.75493479, -45.5170352, - -6.74694450e5], - "exp": [1, 2, 5, 16, 43, 110]} - _rhoG = { - "eq": 4, - "ao": [-2.0315024, -2.6830294, -5.38626492, -17.2991605, -44.7586581, - -63.9201063], - "exp": [1, 2, 4, 9, 18.5, 35.5]} + _Pv_ao = [-7.85951783, 1.84408259, -11.7866497, 22.6807411, -15.9618719, + 1.80122502] + _Pv_exp = [1.0, 1.5, 3.0, 3.5, 4.0, 7.5] + _rhoL_eq = 2 + _rhoL_ao = [1.99274064, 1.09965342, -0.510839303, -1.75493479, -45.5170352, + -6.74694450e5] + _rhoL_exp = [1.0, 2.0, 5.0, 16.0, 43.0, 110] + _rhoG_eq = 4 + _rhoG_ao = [-2.0315024, -2.6830294, -5.38626492, -17.2991605, -44.7586581, + -63.9201063] + _rhoG_exp = [1.0, 2.0, 4.0, 9.0, 18.5, 35.5] def _phi0(self, tau: float, delta: float) -> Dict[str, float]: """Low temperature extension of the IAPWS-95""" @@ -2747,18 +2760,15 @@ class D2O(MEoS): "gamma3": [1.5414, 1.3794, 1.7385, 1.3045, 2.7242, 3.5321, 2.4552, 0.8319, 1.3500, 2.5617, 1.0491, 1.0486]} - _Pv = { - "ao": [-0.80236e1, 0.23957e1, -0.42639e2, 0.99569e2, -0.62135e2], - "exp": [1.0, 1.5, 2.75, 3.0, 3.2]} - _rhoL = { - "eq": 1, - "ao": [0.26406e1, 0.97090e1, -0.18058e2, 0.87202e1, -0.74487e1], - "exp": [0.3678, 1.9, 2.2, 2.63, 7.3]} - _rhoG = { - "eq": 3, - "ao": [-0.37651e1, -0.38673e2, 0.73024e2, -0.13251e3, 0.75235e2, - -0.70412e2], - "exp": [0.409, 1.766, 2.24, 3.04, 3.42, 6.9]} + _Pv_ao = [-0.80236e1, 0.23957e1, -0.42639e2, 0.99569e2, -0.62135e2] + _Pv_exp = [1.0, 1.5, 2.75, 3.0, 3.2] + _rhoL_eq = 1 + _rhoL_ao = [0.26406e1, 0.97090e1, -0.18058e2, 0.87202e1, -0.74487e1] + _rhoL_exp = [0.3678, 1.9, 2.2, 2.63, 7.3] + _rhoG_eq = 3 + _rhoG_ao = [-0.37651e1, -0.38673e2, 0.73024e2, -0.13251e3, 0.75235e2, + -0.70412e2] + _rhoG_exp = [0.409, 1.766, 2.24, 3.04, 3.42, 6.9] def _visco(self, rho: float, T: float, fase) -> float: return _D2O_Viscosity(rho, T) From 3c091b77018781fe23b0aba5bb582d9067bd7a78 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sun, 14 Mar 2021 20:48:01 -0400 Subject: [PATCH 043/102] Increase typing errors from ~50 to ~150 by typing _fase. This commit contains nothing but typing changes, execept for the addition of a default value (None) for fase parameters in several places where the fase isn't even used. --- iapws/_iapws.py | 7 ++-- iapws/_utils.py | 98 +++++++++++++++++++++++------------------------ iapws/ammonia.py | 9 ++++- iapws/humidAir.py | 10 +++-- iapws/iapws95.py | 14 ++++--- iapws/iapws97.py | 2 +- 6 files changed, 75 insertions(+), 65 deletions(-) diff --git a/iapws/_iapws.py b/iapws/_iapws.py index 0b22626..e5b4be0 100644 --- a/iapws/_iapws.py +++ b/iapws/_iapws.py @@ -31,10 +31,11 @@ from cmath import log as log_c from math import log, exp, tan, atan, acos, sin, pi, log10, copysign import warnings -from typing import Dict, Optional, Any +from typing import Dict, Optional from scipy.optimize import minimize +from ._utils import _fase # Constants M = 18.015268 # g/mol @@ -700,7 +701,7 @@ def _Melting_Pressure(T: float, ice: str = "Ih") -> float: # Transport properties -def _Viscosity(rho: float, T: float, fase: Optional[Any] = None, +def _Viscosity(rho: float, T: float, fase: Optional[_fase] = None, drho: float = None) -> float: """Equation for the Viscosity @@ -790,7 +791,7 @@ def _Viscosity(rho: float, T: float, fase: Optional[Any] = None, return mu*1e-6 -def _ThCond(rho: float, T: float, fase: Optional[Any] = None, +def _ThCond(rho: float, T: float, fase: Optional[_fase] = None, drho: Optional[float] = None) -> float: """Equation for the thermal conductivity diff --git a/iapws/_utils.py b/iapws/_utils.py index 8b89404..9ad94d4 100644 --- a/iapws/_utils.py +++ b/iapws/_utils.py @@ -12,7 +12,7 @@ """ from __future__ import division -from typing import Any +from typing import Optional, Any def getphase(Tc: float, Pc: float, T: float, P: float, x: float, region: int) -> str: @@ -65,60 +65,60 @@ def getphase(Tc: float, Pc: float, T: float, P: float, x: float, region: int) -> class _fase(object): """Class to implement a null phase""" - v = None - rho = None + v: Optional[float] = None + rho: Optional[float] = None - h = None - s = None - u = None - a = None - g = None + h: Optional[float] = None + s: Optional[float] = None + u: Optional[float] = None + a: Optional[float] = None + g: Optional[float] = None - cp = None - cv = None - cp_cv = None - w = None - Z = None - fi = None - f = None + cp: Optional[float] = None + cv: Optional[float] = None + cp_cv: Optional[float] = None + w: Optional[float] = None + Z: Optional[float] = None + fi: Optional[float] = None + f: Optional[float] = None - mu = None - k = None - nu = None - Prandt = None - epsilon = None - alfa = None - n = None + mu: Optional[float] = None + k: Optional[float] = None + nu: Optional[float] = None + Prandt: Optional[float] = None + epsilon: Optional[float] = None + alfa: Optional[float] = None + n: Optional[float] = None - alfap = None - betap = None - joule = None - Gruneisen = None - alfav = None - kappa = None - betas = None - gamma = None - Kt = None - kt = None - Ks = None - ks = None - dpdT_rho = None - dpdrho_T = None - drhodT_P = None - drhodP_T = None - dhdT_rho = None - dhdT_P = None - dhdrho_T = None - dhdrho_P = None - dhdP_T = None - dhdP_rho = None + alfap: Optional[float] = None + betap: Optional[float] = None + joule: Optional[float] = None + Gruneisen: Optional[float] = None + alfav: Optional[float] = None + kappa: Optional[float] = None + betas: Optional[float] = None + gamma: Optional[float] = None + Kt: Optional[float] = None + kt: Optional[float] = None + Ks: Optional[float] = None + ks: Optional[float] = None + dpdT_rho: Optional[float] = None + dpdrho_T: Optional[float] = None + drhodT_P: Optional[float] = None + drhodP_T: Optional[float] = None + dhdT_rho: Optional[float] = None + dhdT_P: Optional[float] = None + dhdrho_T: Optional[float] = None + dhdrho_P: Optional[float] = None + dhdP_T: Optional[float] = None + dhdP_rho: Optional[float] = None - Z_rho = None - IntP = None - hInput = None + Z_rho: Optional[float] = None + IntP: Optional[float] = None + hInput: Optional[float] = None -def deriv_H(state: Any, z: str, x: str, y: str, fase) -> float: +def deriv_H(state: Any, z: str, x: str, y: str, fase: _fase) -> float: r"""Calculate generic partial derivative :math:`\left.\frac{\partial z}{\partial x}\right|_{y}` from a fundamental helmholtz free energy equation of state @@ -193,7 +193,7 @@ def deriv_H(state: Any, z: str, x: str, y: str, fase) -> float: return mul*deriv -def deriv_G(state: Any, z: str, x: str, y: str, fase) -> float: +def deriv_G(state: Any, z: str, x: str, y: str, fase: _fase) -> float: r"""Calculate generic partial derivative :math:`\left.\frac{\partial z}{\partial x}\right|_{y}` from a fundamental Gibbs free energy equation of state diff --git a/iapws/ammonia.py b/iapws/ammonia.py index dce9282..9c4294f 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -17,6 +17,7 @@ from scipy.constants import Boltzmann from .iapws95 import MEoS, IAPWS95, mainClassDoc +from ._utils import _fase @mainClassDoc() @@ -84,7 +85,9 @@ class NH3(MEoS): _rhoG_ao = [-.38435, -4.0846, -6.6634, -0.31881e2, 0.21306e3, -0.24648e3] _rhoG_exp = [0.218, 0.55, 1.5, 3.7, 5.5, 5.8] - def _visco(self, rho: float, T: float, fase=None) -> Optional[float]: + def _visco(self, rho: float, T: float, + # fase is unused + fase: Optional[_fase] = None) -> Optional[float]: """Equation for the Viscosity Parameters @@ -138,7 +141,9 @@ def _visco(self, rho: float, T: float, fase=None) -> Optional[float]: mu = muo + mub + mur return mu*1e-6 - def _thermo(self, rho: float, T: float, fase) -> Optional[float]: + def _thermo(self, rho: float, T: float, + # fase is unused + fase: Optional[_fase] = None) -> Optional[float]: """Equation for the thermal conductivity Parameters diff --git a/iapws/humidAir.py b/iapws/humidAir.py index 0529f02..722439c 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -16,13 +16,13 @@ from __future__ import division from math import exp, log, pi, atan import warnings -from typing import Tuple, Dict, Any +from typing import Tuple, Dict, Optional, Any from scipy.optimize import fsolve from ._iapws import M as MW from ._iapws import _Ice -from ._utils import deriv_G +from ._utils import deriv_G, _fase from .iapws95 import MEoS, IAPWS95, mainClassDoc @@ -366,7 +366,9 @@ def _Liquid_Density(cls, T: float) -> float: return rho @staticmethod - def _visco(rho: float, T: float, fase=None) -> float: + def _visco(rho: float, T: float, + # fase is unused + fase: Optional[_fase] = None) -> float: """Equation for the Viscosity Parameters @@ -419,7 +421,7 @@ def _visco(rho: float, T: float, fase=None) -> float: mu = muo+mur return mu*1e-6 - def _thermo(self, rho: float, T: float, fase=None) -> float: + def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: """Equation for the thermal conductivity Parameters diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 4dce205..496d8ba 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -17,7 +17,7 @@ from numpy import exp, log, ndarray from scipy.optimize import fsolve -from typing import Tuple, Dict, Optional, List +from typing import Tuple, Dict, Optional, List, Any from .iapws97 import _TSat_P, IAPWS97 from ._iapws import M, Tc, Pc, rhoc, Tc_D2O, Pc_D2O, rhoc_D2O @@ -1508,7 +1508,7 @@ def t_func(T: float) -> float: cp0.v = self.v0 self.gamma0 = -self.v0/self.P/1000*self.derivative("P", "v", "s", cp0) - def fill(self, fase, estado): + def fill(self, fase: _fase, estado: Dict[str, Any]) -> None: """Fill phase properties""" fase.rho = estado["rho"] fase.v = 1/fase.rho @@ -2637,14 +2637,14 @@ def _Vapor_Entropy(cls, T: float) -> float: s = phi+dpdT/rho*1000 return s - def _visco(self, rho: float, T: float, fase: Optional[Dict[str, float]]) -> float: + def _visco(self, rho: float, T: float, fase: Optional[_fase]) -> float: ref = IAPWS95() st = ref._Helmholtz(rho, 1.5*Tc) delta = rho/rhoc drho = 1e3/self.R/1.5/Tc/(1+2*delta*st["fird"]+delta**2*st["firdd"]) return _Viscosity(rho, T, fase, drho) - def _thermo(self, rho: float, T: float, fase: Optional[Dict[str, float]]) -> float: + def _thermo(self, rho: float, T: float, fase: Optional[_fase]) -> float: ref = IAPWS95() st = ref._Helmholtz(rho, 1.5*Tc) delta = rho/rhoc @@ -2770,10 +2770,12 @@ class D2O(MEoS): -0.70412e2] _rhoG_exp = [0.409, 1.766, 2.24, 3.04, 3.42, 6.9] - def _visco(self, rho: float, T: float, fase) -> float: + def _visco(self, rho: float, T: float, + fase: Optional[_fase] = None) -> float: # fase is unused return _D2O_Viscosity(rho, T) - def _thermo(self, rho: float, T: float, fase) -> float: + def _thermo(self, rho: float, T: float, + fase: Optional[_fase] = None) -> float: # fase is unused return _D2O_ThCond(rho, T) def _surface(self, T: float) -> float: diff --git a/iapws/iapws97.py b/iapws/iapws97.py index 12e064b..26f6e78 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -4676,7 +4676,7 @@ def rho_funcion(rho: float) -> float: self.Hvap = vapor["h"]-liquido["h"] self.Svap = vapor["s"]-liquido["s"] - def fill(self, fase, estado: Dict[str, float]): + def fill(self, fase: _fase, estado: Dict[str, float]): """Fill phase properties""" fase.v = estado["v"] fase.rho = 1/fase.v From e1a702d6a86530c8d42cea04ecec1b542d891616 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sun, 14 Mar 2021 21:37:49 -0400 Subject: [PATCH 044/102] Reduce type errors surrounding fase. Declare a bunch of variables in fase that appear to have been overlooked... Or maybe I misunderstand what an _fase object is and the whole system is heavily dynamically typed? Also several assertions to document types of unclear origin, and suppress mypy errors about those types. --- iapws/_utils.py | 34 ++++++++++++++++++++++++++++++++-- iapws/iapws95.py | 10 ++++++++-- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/iapws/_utils.py b/iapws/_utils.py index 9ad94d4..1b41a59 100644 --- a/iapws/_utils.py +++ b/iapws/_utils.py @@ -117,6 +117,20 @@ class _fase(object): IntP: Optional[float] = None hInput: Optional[float] = None + # Properties added because various methods set/access them? + xkappa: Optional[float] = None + kappas: Optional[float] = None + deltat: Optional[float] = None + rhoM: Optional[float] = None + M: Optional[float] = None + hM: Optional[float] = None + sM: Optional[float] = None + uM: Optional[float] = None + aM: Optional[float] = None + gM: Optional[float] = None + cvM: Optional[float] = None + cpM: Optional[float] = None + def deriv_H(state: Any, z: str, x: str, y: str, fase: _fase) -> float: r"""Calculate generic partial derivative @@ -163,16 +177,24 @@ def deriv_H(state: Any, z: str, x: str, y: str, fase: _fase) -> float: # We use the relation between rho and v and his partial derivative # ∂v/∂b|c = -1/ρ² ∂ρ/∂b|c # ∂a/∂v|c = -ρ² ∂a/∂ρ|c - mul = 1 + mul = 1.0 if z == "rho": + assert(isinstance(fase.rho, float)) mul = -fase.rho**2 z = "v" if x == "rho": + assert(isinstance(fase.rho, float)) mul = -1/fase.rho**2 x = "v" if y == "rho": y = "v" + assert(isinstance(fase.alfap, float)) + assert(isinstance(fase.betap, float)) + assert(isinstance(fase.v, float)) + assert(isinstance(fase.cv, float)) + assert(isinstance(fase.s, float)) + dT = {"P": state.P*1000*fase.alfap, "T": 1, "v": 0, @@ -235,14 +257,22 @@ def deriv_G(state: Any, z: str, x: str, y: str, fase: _fase) -> float: IAPWS, Revised Advisory Note No. 3: Thermodynamic Derivatives from IAPWS Formulations, http://www.iapws.org/relguide/Advise3.pdf """ - mul = 1 + mul = 1.0 if z == "rho": + assert(isinstance(fase.rho, float)) mul = -fase.rho**2 z = "v" if x == "rho": + assert(isinstance(fase.rho, float)) mul = -1/fase.rho**2 x = "v" + assert(isinstance(fase.alfav, float)) + assert(isinstance(fase.v, float)) + assert(isinstance(fase.cp, float)) + assert(isinstance(fase.s, float)) + assert(isinstance(fase.xkappa, float)) + dT = {"P": 0, "T": 1, "v": fase.v*fase.alfav, diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 496d8ba..2a5eed9 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -17,7 +17,7 @@ from numpy import exp, log, ndarray from scipy.optimize import fsolve -from typing import Tuple, Dict, Optional, List, Any +from typing import Tuple, Dict, Optional, List from .iapws97 import _TSat_P, IAPWS97 from ._iapws import M, Tc, Pc, rhoc, Tc_D2O, Pc_D2O, rhoc_D2O @@ -418,6 +418,7 @@ def __init__(self, **kwargs): assert(isinstance(self._rhoG_eq, int)) assert(isinstance(self._rhoG_ao, list)) assert(isinstance(self._rhoG_exp, list)) + assert(isinstance(self.M, float)) self.R = self._constants["R"][0]/self._constants.get("M", self.M) self.Zc = self.Pc/self.rhoc/self.R/self.Tc @@ -1508,11 +1509,16 @@ def t_func(T: float) -> float: cp0.v = self.v0 self.gamma0 = -self.v0/self.P/1000*self.derivative("P", "v", "s", cp0) - def fill(self, fase: _fase, estado: Dict[str, Any]) -> None: + def fill(self, fase: _fase, estado: Dict[str, float]) -> None: """Fill phase properties""" fase.rho = estado["rho"] fase.v = 1/fase.rho + assert(self.P is not None) + assert(self.T is not None) + assert(isinstance(self.M, float)) + assert(isinstance(self.R, float)) + fase.h = estado["h"] fase.s = estado["s"] fase.u = fase.h-self.P*1000*fase.v From d6b7690d616a7002b097a162d4fd15ff215424dc Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sun, 14 Mar 2021 21:44:42 -0400 Subject: [PATCH 045/102] Are HumidAir and SeaWater valid _fase objects? They're passed in contexts that seem to imply that they are, but it is also pretty unclear to me what the _fase object provides since all of it's properties are initialized to None. --- iapws/humidAir.py | 4 ++-- iapws/iapws08.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iapws/humidAir.py b/iapws/humidAir.py index 722439c..c445b9e 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -22,7 +22,7 @@ from ._iapws import M as MW from ._iapws import _Ice -from ._utils import deriv_G, _fase +from ._utils import _fase, deriv_G from .iapws95 import MEoS, IAPWS95, mainClassDoc @@ -518,7 +518,7 @@ def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: return k*1e-3 -class HumidAir(object): +class HumidAir(_fase): """ Humid air class with complete functionality diff --git a/iapws/iapws08.py b/iapws/iapws08.py index 288fc27..b883e14 100644 --- a/iapws/iapws08.py +++ b/iapws/iapws08.py @@ -28,7 +28,7 @@ from .iapws95 import IAPWS95 from .iapws97 import IAPWS97, _Region1, _Region2 from ._iapws import _ThCond, Tc, Pc, rhoc, _Ice, _Tension -from ._utils import deriv_G +from ._utils import _fase, deriv_G # Constants @@ -42,7 +42,7 @@ To = 273.15 -class SeaWater(object): +class SeaWater(_fase): """ Class to model seawater with standard IAPWS-08 From ed42744f5c10f2cbb1a99f4c1ab73eabbd834a22 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sun, 14 Mar 2021 22:51:27 -0400 Subject: [PATCH 046/102] Better consistency for _visco() and _thermo(). This is first commit that has really changed tests.py. I don't understand why all of the other classes would implement _visco() as an object method, while Air implemented it as a static method. Air even went to the trouble of accepting an optional fase parameter, that wasn't actually required because the _visco static method had no relationship to the unimplemented object method of the same name? The cleanest fix in my opinion is to be more explicit that derived classes are expected to implement _visco() and _thermo(), have Air do so properly as a class derived from MEoS. The change to the tests was minor, the method is ostensibly part of the private API, and it's consistent with the _thermo() tests immediately below. --- iapws/ammonia.py | 10 ++++------ iapws/humidAir.py | 8 +++----- iapws/iapws95.py | 20 ++++++++++++++------ test.py | 14 +++++++------- 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/iapws/ammonia.py b/iapws/ammonia.py index 9c4294f..14f511b 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -85,9 +85,8 @@ class NH3(MEoS): _rhoG_ao = [-.38435, -4.0846, -6.6634, -0.31881e2, 0.21306e3, -0.24648e3] _rhoG_exp = [0.218, 0.55, 1.5, 3.7, 5.5, 5.8] - def _visco(self, rho: float, T: float, - # fase is unused - fase: Optional[_fase] = None) -> Optional[float]: + # fase is unused + def _visco(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: """Equation for the Viscosity Parameters @@ -141,9 +140,8 @@ def _visco(self, rho: float, T: float, mu = muo + mub + mur return mu*1e-6 - def _thermo(self, rho: float, T: float, - # fase is unused - fase: Optional[_fase] = None) -> Optional[float]: + # fase is unused + def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> Optional[float]: """Equation for the thermal conductivity Parameters diff --git a/iapws/humidAir.py b/iapws/humidAir.py index c445b9e..4e2036d 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -365,10 +365,8 @@ def _Liquid_Density(cls, T: float) -> float: rho = suma*rhoc return rho - @staticmethod - def _visco(rho: float, T: float, - # fase is unused - fase: Optional[_fase] = None) -> float: + # fase is unused + def _visco(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: """Equation for the Viscosity Parameters @@ -421,7 +419,7 @@ def _visco(rho: float, T: float, mu = muo+mur return mu*1e-6 - def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: + def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> Optional[float]: """Equation for the thermal conductivity Parameters diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 2a5eed9..7de620b 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -1509,6 +1509,14 @@ def t_func(T: float) -> float: cp0.v = self.v0 self.gamma0 = -self.v0/self.P/1000*self.derivative("P", "v", "s", cp0) + # Derived classes must implement _visco to call fill() + def _visco(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: + raise NotImplementedError + + # Derived classes must implement _thermo to call fill() + def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> Optional[float]: + raise NotImplementedError + def fill(self, fase: _fase, estado: Dict[str, float]) -> None: """Fill phase properties""" fase.rho = estado["rho"] @@ -2643,14 +2651,14 @@ def _Vapor_Entropy(cls, T: float) -> float: s = phi+dpdT/rho*1000 return s - def _visco(self, rho: float, T: float, fase: Optional[_fase]) -> float: + def _visco(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: ref = IAPWS95() st = ref._Helmholtz(rho, 1.5*Tc) delta = rho/rhoc drho = 1e3/self.R/1.5/Tc/(1+2*delta*st["fird"]+delta**2*st["firdd"]) return _Viscosity(rho, T, fase, drho) - def _thermo(self, rho: float, T: float, fase: Optional[_fase]) -> float: + def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> Optional[float]: ref = IAPWS95() st = ref._Helmholtz(rho, 1.5*Tc) delta = rho/rhoc @@ -2776,12 +2784,12 @@ class D2O(MEoS): -0.70412e2] _rhoG_exp = [0.409, 1.766, 2.24, 3.04, 3.42, 6.9] - def _visco(self, rho: float, T: float, - fase: Optional[_fase] = None) -> float: # fase is unused + # fase is unused + def _visco(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: return _D2O_Viscosity(rho, T) - def _thermo(self, rho: float, T: float, - fase: Optional[_fase] = None) -> float: # fase is unused + # fase is unused + def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> Optional[float]: return _D2O_ThCond(rho, T) def _surface(self, T: float) -> float: diff --git a/test.py b/test.py index 44d4040..19add97 100755 --- a/test.py +++ b/test.py @@ -2382,14 +2382,14 @@ def test_Air(self): def test_AirTransport(self): """Table V, pag 28""" - self.assertEqual(round(Air._visco(0, 100), 11), 7.09559e-6) - self.assertEqual(round(Air._visco(0, 300), 10), 18.523e-6) - self.assertEqual(round(Air._visco(28*28.9586, 100), 9), 107.923e-6) - self.assertEqual(round(Air._visco(10*28.9586, 200), 10), 21.1392e-6) - self.assertEqual(round(Air._visco(5*28.9586, 300), 10), 21.3241e-6) - self.assertEqual(round(Air._visco(10.4*28.9586, 132.64), 10), 17.7623e-6) - st = Air() + self.assertEqual(round(st._visco(0, 100), 11), 7.09559e-6) + self.assertEqual(round(st._visco(0, 300), 10), 18.523e-6) + self.assertEqual(round(st._visco(28*28.9586, 100), 9), 107.923e-6) + self.assertEqual(round(st._visco(10*28.9586, 200), 10), 21.1392e-6) + self.assertEqual(round(st._visco(5*28.9586, 300), 10), 21.3241e-6) + self.assertEqual(round(st._visco(10.4*28.9586, 132.64), 10), 17.7623e-6) + self.assertEqual(round(st._thermo(0, 100), 8), 9.35902e-3) self.assertEqual(round(st._thermo(0, 300), 7), 26.3529e-3) self.assertEqual(round(Air(rho=28*28.9586, T=100).k, 6), 119.222e-3) From 51f41088b5756811a5f92f355d911c4ea7b92ada Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sun, 14 Mar 2021 23:46:12 -0400 Subject: [PATCH 047/102] Region is actually an optional int despite the documentation. --- iapws/iapws97.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iapws/iapws97.py b/iapws/iapws97.py index 26f6e78..0d510a1 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -3993,7 +3993,7 @@ def _Bound_Ps(P: float, s: float) -> Optional[int]: return region -def _Bound_hs(h: float, s: float) -> float: +def _Bound_hs(h: float, s: float) -> Optional[int]: """Region definition for input h and s Parameters From c452989b2899572f63ae3f2e644d89bda6565896 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sun, 14 Mar 2021 23:46:54 -0400 Subject: [PATCH 048/102] More mypy error suppresion mostly through assertions. Also renamed t to te5 to avoid confusion t below. --- iapws/_iapws.py | 11 +++++++++-- iapws/humidAir.py | 27 +++++++++++++++++---------- iapws/iapws08.py | 6 ++++++ 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/iapws/_iapws.py b/iapws/_iapws.py index e5b4be0..631f8fa 100644 --- a/iapws/_iapws.py +++ b/iapws/_iapws.py @@ -751,6 +751,8 @@ def _Viscosity(rho: float, T: float, fase: Optional[_fase] = None, # Critical enhancement if fase and drho: + assert(isinstance(fase.drhodP_T, float)) + qc = 1/1.9 qd = 1/1.1 @@ -845,6 +847,11 @@ def _ThCond(rho: float, T: float, fase: Optional[_fase] = None, # Critical enhancement if fase: + assert(isinstance(fase.drhodP_T, float)) + assert(isinstance(fase.cp, float)) + assert(isinstance(fase.cp_cv, float)) + assert(isinstance(fase.mu, float)) + R = 0.46151805 if not drho: @@ -865,7 +872,7 @@ def _ThCond(rho: float, T: float, fase: Optional[_fase] = None, else: ai = [1.11999926419994, 0.595748562571649, 9.88952565078920, -10.3255051147040, 4.66861294457414, -0.503243546373828] - drho = 1/sum(a*d**i for i, a in enumerate(ai))*rhoc/Pc + drho = 1.0/sum(a*d**i for i, a in enumerate(ai))*rhoc/Pc DeltaX = d*(Pc/rhoc*fase.drhodP_T-Pc/rhoc*drho*1.5/Tr) if DeltaX < 0: @@ -876,7 +883,7 @@ def _ThCond(rho: float, T: float, fase: Optional[_fase] = None, # Eq 19 if y < 1.2e-7: - Z = 0 + Z = 0.0 else: Z = 2/pi/y*(((1-1/fase.cp_cv)*atan(y)+y/fase.cp_cv)-( 1-exp(-1/(1/y+y**2/3/d**2)))) diff --git a/iapws/humidAir.py b/iapws/humidAir.py index 4e2036d..84ff917 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -461,8 +461,8 @@ def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> Optiona # Eq 5 N = [1.308, 1.405, -1.036] - t = [-1.1, -0.3] - lo = N[0]*muo+N[1]*tau**t[0]+N[2]*tau**t[1] + te5 = [-1.1, -0.3] + lo = N[0]*muo+N[1]*tau**te5[0]+N[2]*tau**te5[1] n_poly = [8.743, 14.76, -16.62, 3.793, -6.142, -0.3778] t_poly = [0.1, 0, 0.5, 2.7, 0.3, 1.3] @@ -478,6 +478,8 @@ def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> Optiona lc = 0.0 # FIXME: Tiny desviation in the test in paper, 0.06% at critical point if fase: + assert(isinstance(fase.drhodP_T, float)) + qd = 0.31 Gamma = 0.055 Xio = 0.11 @@ -496,6 +498,10 @@ def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> Optiona # Eq 10 bracket = X-Xref*Tref/T if bracket > 0: + assert(isinstance(fase.cp, float)) + assert(isinstance(fase.cv, float)) + assert(isinstance(fase.mu, float)) + Xi = Xio*(bracket/Gamma)**(0.63/1.2415) Xq = Xi/qd @@ -645,23 +651,22 @@ def calculo(self) -> None: xa = self.kwargs["xa"] assert(isinstance(xa, float)) A = xa/(1-(1-xa)*(1-MW/Ma)) + assert(isinstance(A, float)) # Thermodynamic definition if self._mode == "TP": - - def rho_func(rho: float) -> float: - fav = self._fav(T, rho, A) - return rho**2*fav["fird"]/1000-P + def rho_func(rhopar: float) -> float: + fav = self._fav(T, rhopar, A) + return rhopar**2*fav["fird"]/1000-P rho = fsolve(rho_func, 1)[0] elif self._mode == "Prho": - - def t_func(T: float) -> float: - fav = self._fav(T, rho, A) + def t_func(Tpar: float) -> float: + fav = self._fav(Tpar, rho, A) return rho**2*fav["fird"]/1000-P T = fsolve(t_func, 300)[0] + assert(T is not None) assert(isinstance(rho, float)) - assert(isinstance(A, float)) # General calculation procedure fav = self._fav(T, rho, A) @@ -726,6 +731,8 @@ def _eq(self, T: float, P: float) -> float: gw = ice["g"] else: water = IAPWS95(T=T, P=P) + # water.g is actually a numpy.float64? + assert(water.g is not None) gw = water.g def f(parr: Tuple[float, float]) -> Tuple[float, float]: diff --git a/iapws/iapws08.py b/iapws/iapws08.py index b883e14..1f48c39 100644 --- a/iapws/iapws08.py +++ b/iapws/iapws08.py @@ -266,6 +266,12 @@ def _water(cls, T: float, P: float) -> Dict[str, float]: water = IAPWS95(P=P, T=T) assert(isinstance(water.h, float)) assert(isinstance(water.s, float)) + assert(isinstance(water.rho, float)) + assert(isinstance(water.cp, float)) + assert(isinstance(water.betas, float)) + assert(isinstance(water.w, float)) + assert(isinstance(water.k, float)) + prop = {} prop["g"] = water.h-T*water.s prop["gt"] = -water.s From 4f619c356555cff9ff2c35e0af5683cfad0afb93 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Mon, 15 Mar 2021 01:27:08 -0400 Subject: [PATCH 049/102] Some asserts enforcing dict keys and value types. --- iapws/iapws95.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 7de620b..ed3b41d 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -1519,11 +1519,19 @@ def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> Optiona def fill(self, fase: _fase, estado: Dict[str, float]) -> None: """Fill phase properties""" + assert("rho" in estado and isinstance(estado["rho"], float)) + assert("h" in estado and isinstance(estado["h"], float)) + assert("s" in estado and isinstance(estado["s"], float)) + assert("fir" in estado and isinstance(estado["fir"], float)) + assert("fird" in estado and isinstance(estado["fird"], float)) + assert("delta" in estado and isinstance(estado["delta"], float)) + assert("cv" in estado and isinstance(estado["cv"], float)) + assert("alfap" in estado and isinstance(estado["alfap"], float)) + assert("betap" in estado and isinstance(estado["betap"], float)) + fase.rho = estado["rho"] fase.v = 1/fase.rho - assert(self.P is not None) - assert(self.T is not None) assert(isinstance(self.M, float)) assert(isinstance(self.R, float)) From 0ef11e0bac8a3890eeefdf42bc646568d8791743 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Mon, 15 Mar 2021 02:13:20 -0400 Subject: [PATCH 050/102] Try to be quite a bit clearer about the origin of R and M. I'm into code that I that don't understand here, but this makes it much easier to tell where these values come from. The _constants.get("M") was particuilarly cvonfusing since no class defines "M" in their constants dictionary, making it equivalent to self.M as far as I can tell. Better names can be put on the global_M and global_R once I'm confident I understand what they are. --- iapws/_iapws.py | 8 ++++---- iapws/ammonia.py | 3 +-- iapws/humidAir.py | 14 ++++++++------ iapws/iapws95.py | 17 ++++++++--------- iapws/iapws97.py | 16 +++++++++++++--- 5 files changed, 34 insertions(+), 24 deletions(-) diff --git a/iapws/_iapws.py b/iapws/_iapws.py index 631f8fa..bc4e3bd 100644 --- a/iapws/_iapws.py +++ b/iapws/_iapws.py @@ -38,8 +38,8 @@ from ._utils import _fase # Constants -M = 18.015268 # g/mol -R = 0.461526 # kJ/kg·K +_global_M = 18.015268 # g/mol +_global_R = 0.461526 # kJ/kg·K # Table 1 from Release on the Values of Temperature, Pressure and Density of # Ordinary and Heavy Water Substances at their Respective Critical Points @@ -998,8 +998,8 @@ def _Dielectric(rho: float, T: float) -> float: g = 1+n[11]*d/(Tc/228/Tr-1)**1.2 for i in range(11): g += n[i]*d**I[i]*Tr**J[i] - A = Na*mu**2*rho*g/M*1000/epsilon0/k/T - B = Na*alfa*rho/3/M*1000/epsilon0 + A = Na*mu**2*rho*g/_global_M*1000/epsilon0/k/T + B = Na*alfa*rho/3/_global_M*1000/epsilon0 e = (1+A+5*B+(9+2*A+18*B+A**2+10*A*B+9*B**2)**0.5)/4/(1-B) return e diff --git a/iapws/ammonia.py b/iapws/ammonia.py index 14f511b..c074d75 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -52,9 +52,8 @@ class NH3(MEoS): "ao_exp": [], "titao": [], "ao_hyp": [], "hyp": []} + _constant_R = 8.314471 _constants = { - "R": [8.314471], - "nr1": [-0.1858814e01, 0.4554431e-1, 0.7238548, 0.1229470e-1, 0.2141882e-10], "d1": [1, 2, 1, 4, 15], diff --git a/iapws/humidAir.py b/iapws/humidAir.py index 84ff917..2450dc0 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -20,7 +20,7 @@ from scipy.optimize import fsolve -from ._iapws import M as MW +from ._iapws import _global_M from ._iapws import _Ice from ._utils import _fase, deriv_G from .iapws95 import MEoS, IAPWS95, mainClassDoc @@ -296,8 +296,8 @@ class Air(MEoSBlend): "sum2": [2./3], } + _constant_R = 8.31451 _constants = { - "R": [8.31451], "Tref": [132.6312], "rhoref": [10.4477*Ma], "nr1": [0.118160747229, 0.713116392079, -0.161824192067e1, @@ -650,7 +650,7 @@ def calculo(self) -> None: elif self._composition == "xa": xa = self.kwargs["xa"] assert(isinstance(xa, float)) - A = xa/(1-(1-xa)*(1-MW/Ma)) + A = xa/(1-(1-xa)*(1-_global_M/Ma)) assert(isinstance(A, float)) # Thermodynamic definition @@ -701,7 +701,7 @@ def t_func(Tpar: float) -> float: # Saturation related properties A_sat = self._eq(self.T, self.P) - self.xa_sat = A_sat*MW/Ma/(1-A_sat*(1-MW/Ma)) + self.xa_sat = A_sat*_global_M/Ma/(1-A_sat*(1-_global_M/Ma)) self.RH = (1-self.xa)/(1-self.xa_sat) def derivative(self, z: str, x: str, y: str): @@ -830,12 +830,14 @@ def _coligative(self, rho: float, A: float, fav: Dict[str, float]) -> Dict[str, Thermodynamic Properties of Seawater, Table 12, http://www.iapws.org/relguide/SeaAir.html """ + Mw = _global_M + prop = {} prop["mu"] = fav["fira"] prop["muw"] = fav["fir"]+rho*fav["fird"]-A*fav["fira"] - prop["M"] = 1/((1-A)/MW+A/Ma) + prop["M"] = 1/((1-A)/Mw+A/Ma) prop["HR"] = 1/A-1 - prop["xa"] = A*MW/Ma/(1-A*(1-MW/Ma)) + prop["xa"] = A*Mw/Ma/(1-A*(1-Mw/Ma)) prop["xw"] = 1-prop["xa"] return prop diff --git a/iapws/iapws95.py b/iapws/iapws95.py index ed3b41d..9018163 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -20,7 +20,7 @@ from typing import Tuple, Dict, Optional, List from .iapws97 import _TSat_P, IAPWS97 -from ._iapws import M, Tc, Pc, rhoc, Tc_D2O, Pc_D2O, rhoc_D2O +from ._iapws import _global_M, Tc, Pc, rhoc, Tc_D2O, Pc_D2O, rhoc_D2O from ._iapws import _Viscosity, _ThCond, _Dielectric, _Refractive, _Tension from ._iapws import _D2O_Viscosity, _D2O_ThCond, _D2O_Tension from ._utils import _fase, getphase, deriv_H @@ -420,7 +420,7 @@ def __init__(self, **kwargs): assert(isinstance(self._rhoG_exp, list)) assert(isinstance(self.M, float)) - self.R = self._constants["R"][0]/self._constants.get("M", self.M) + self.R = self.__class__._constant_R/self.M self.Zc = self.Pc/self.rhoc/self.R/self.Tc self.kwargs = MEoS.kwargs.copy() self.__call__(**kwargs) @@ -534,7 +534,7 @@ def calculo(self): To = 300 rhoo = 900 - self.R = self._constants["R"][0]/self._constants.get("M", self.M) + self.R = self._constant_R/self.M rhoc = self._constants.get("rhoref", [self.rhoc])[0] Tc = self._constants.get("Tref", [self.Tc])[0] @@ -2072,7 +2072,6 @@ def _derivDimensional(self, rho: float, T: float) -> Dict[str, float]: prop["firdd"] = 0.0 return prop - R = self._constants.get("R")[0]/self._constants.get("M", self.M) rhoc = self._constants.get("rhoref", [self.rhoc])[0] Tc = self._constants.get("Tref", [self.Tc])[0] delta = rho/rhoc @@ -2093,6 +2092,8 @@ def _derivDimensional(self, rho: float, T: float) -> Dict[str, float]: firdd = res["firdd"] firdt = res["firdt"] + R = self.R + prop = {} prop["fir"] = R*T*(fio+fir) prop["firt"] = R*(fio+fir-(fiot+firt)*tau) @@ -2391,7 +2392,7 @@ class IAPWS95(MEoS): Tc = Tc rhoc = rhoc Pc = Pc - M = M + M = _global_M Tt = 273.16 Tb = 373.1243 f_acent = 0.3443 @@ -2404,9 +2405,8 @@ class IAPWS95(MEoS): "titao": [1.28728967, 3.53734222, 7.74073708, 9.24437796, 27.5075105]} + _constant_R = 8.314371357587 _constants = { - "R": [8.314371357587], - "nr1": [0.12533547935523e-1, 0.78957634722828e1, -0.87803203303561e1, 0.31802509345418, -0.26145533859358, -0.78199751687981e-2, 0.88089493102134e-2], @@ -2752,9 +2752,8 @@ class D2O(MEoS): "titao": [308/Tc, 1695/Tc, 3949/Tc, 10317/Tc], "ao_hyp": [], "hyp": []} + _constant_R = 8.3144598 _constants = { - "R": [8.3144598], - "nr1": [0.122082060e-1, 0.296956870e1, -0.379004540e1, 0.941089600, -0.922466250, -0.139604190e-1], "d1": [4, 1, 1, 2, 2, 3], diff --git a/iapws/iapws97.py b/iapws/iapws97.py index 0d510a1..c593d91 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -88,7 +88,7 @@ from scipy.optimize import fsolve, newton -from ._iapws import R, Tc, Pc, rhoc, Tt, Pt, Tb, Dipole, f_acent +from ._iapws import _global_R, Tc, Pc, rhoc, Tt, Pt, Tb, Dipole, f_acent from ._iapws import _Viscosity, _ThCond, _Tension, _Dielectric, _Refractive from ._utils import getphase, deriv_G, _fase @@ -785,6 +785,8 @@ def _Region1(T: float, P: float) -> Dict[str, float]: gtt += n*j*(j-1) * (7.1-Pr)**i * (Tr-1.222)**(j-2) gpt -= n*i*j * (7.1-Pr)**(i-1) * (Tr-1.222)**(j-1) + R = _global_R + propiedades = {} propiedades["T"] = T propiedades["P"] = P @@ -1036,6 +1038,8 @@ def _Region2(T: float, P: float) -> Dict[str, float]: grtt += ni*j*(j-1) * Pr**i * (Tr-0.5)**(j-2) grpt += ni*i*j * Pr**(i-1) * (Tr-0.5)**(j-1) + R = _global_R + propiedades = {} propiedades["T"] = T propiedades["P"] = P @@ -1848,6 +1852,8 @@ def _Region3(rho: float, T: float) -> Dict[str, float]: gtt += n*j*(j-1) * d**i * Tr**(j-2) gdt += n*i*j * d**(i-1) * Tr**(j-1) + R = _global_R + propiedades = {} propiedades["T"] = T propiedades["P"] = d*gd*R*T*rho/1000 @@ -3742,6 +3748,8 @@ def _Region5(T: float, P: float) -> Dict[str, float]: grtt += ni*j*(j-1) * Pr**i * Tr**(j-2) grpt += ni*i*j * Pr**(i-1) * Tr**(j-1) + R = _global_R + propiedades = {} propiedades["T"] = T propiedades["P"] = P @@ -4198,6 +4206,8 @@ def prop0(T: float, P: float) -> Dict[str, float]: Pr = P/1. go, gop, gopp, got, gott, gopt = Region5_cp0(Tr, Pr) + R = _global_R + prop0 = {} prop0["v"] = Pr*gop*R*T/P/1000 prop0["h"] = Tr*got*R*T @@ -4692,7 +4702,7 @@ def fill(self, fase: _fase, estado: Dict[str, float]): fase.cp_cv = fase.cp/fase.cv fase.w = estado["w"] - fase.Z = self.P*fase.v/R*1000/self.T + fase.Z = self.P*fase.v/_global_R*1000/self.T fase.alfav = estado["alfav"] fase.xkappa = estado["kt"] fase.kappas = -1/fase.v*self.derivative("v", "P", "s", fase) @@ -4704,7 +4714,7 @@ def fill(self, fase: _fase, estado: Dict[str, float]): fase.alfap = fase.alfav/self.P/fase.xkappa fase.betap = -1/self.P*self.derivative("P", "v", "T", fase) - fase.fi = exp((fase.g-self.g0)/R/self.T) + fase.fi = exp((fase.g-self.g0)/_global_R/self.T) fase.f = self.P*fase.fi fase.mu = _Viscosity(fase.rho, self.T) From 52152d924b346960d9a6e6862fe1a8e8a10c8254 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Mon, 15 Mar 2021 14:25:42 -0400 Subject: [PATCH 051/102] Add some mypy stubs for external functions. These aren't intended to be complete, but just what IAPWS uses. --- stubs/matplotlib/__init__.pyi | 5 +++++ stubs/matplotlib/pyplot.pyi | 41 +++++++++++++++++++++++++++++++++++ stubs/numpy/__init__.pyi | 32 +++++++++++++++++++++++++++ stubs/scipy/__init__.pyi | 5 +++++ stubs/scipy/constants.pyi | 7 ++++++ stubs/scipy/optimize.pyi | 40 ++++++++++++++++++++++++++++++++++ stubs/setuptools.pyi | 22 +++++++++++++++++++ 7 files changed, 152 insertions(+) create mode 100644 stubs/matplotlib/__init__.pyi create mode 100644 stubs/matplotlib/pyplot.pyi create mode 100644 stubs/numpy/__init__.pyi create mode 100644 stubs/scipy/__init__.pyi create mode 100644 stubs/scipy/constants.pyi create mode 100644 stubs/scipy/optimize.pyi create mode 100644 stubs/setuptools.pyi diff --git a/stubs/matplotlib/__init__.pyi b/stubs/matplotlib/__init__.pyi new file mode 100644 index 0000000..3d329c9 --- /dev/null +++ b/stubs/matplotlib/__init__.pyi @@ -0,0 +1,5 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +"""IAPWS stubs for matplotlib""" + +# Nothing at top level. diff --git a/stubs/matplotlib/pyplot.pyi b/stubs/matplotlib/pyplot.pyi new file mode 100644 index 0000000..25bc740 --- /dev/null +++ b/stubs/matplotlib/pyplot.pyi @@ -0,0 +1,41 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +"""IAPWS stubs for matplotlib.plylot""" + +from typing import Mapping, Tuple, Optional, Any + +# Just what we need... + +def title(label: str) -> None: + ... + +def xlabel(xlabel: str) -> None: + ... + +def ylabel(ylabel: str) -> None: + ... + +def xlim() -> Tuple[float, float]: + ... + +def ylim() -> Tuple[float, float]: + ... + +def grid(b: Optional[bool] = None) -> None: + ... + +def xscale(value: str) -> None: + ... + +def yscale(value: str) -> None: + ... + +def annotate(txt: str, xy: Tuple[float, float], + rotation: Optional[float] = None, **kwargs) -> None: + ... + +def plot(x: Any, y: Any, **kwargs) -> None: + ... + +def show() -> None: + ... diff --git a/stubs/numpy/__init__.pyi b/stubs/numpy/__init__.pyi new file mode 100644 index 0000000..df8dca1 --- /dev/null +++ b/stubs/numpy/__init__.pyi @@ -0,0 +1,32 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +"""IAPWS stubs for numpy""" + +from typing import Tuple, List, Any + +class Float64(float): + ... + +class ndarray(Tuple[Float64, ...]): + ... + +def linspace(start: Any, stop: Any, num: int = 1) -> ndarray: + ... + +def concatenate(a: List[Any]) -> ndarray: + ... + +def arange(start: Any, stop: Any, step: Any) -> ndarray: + ... + +def log10(Any) -> Float64: + ... + +def log(Any) -> Float64: + ... + +def exp(Any) -> Float64: + ... + +def logspace(start: Any, stop: Any, num: int) -> ndarray: + ... diff --git a/stubs/scipy/__init__.pyi b/stubs/scipy/__init__.pyi new file mode 100644 index 0000000..901debb --- /dev/null +++ b/stubs/scipy/__init__.pyi @@ -0,0 +1,5 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +"""IAPWS stubs for scipy""" + +# Nothing at top level. diff --git a/stubs/scipy/constants.pyi b/stubs/scipy/constants.pyi new file mode 100644 index 0000000..0d431d7 --- /dev/null +++ b/stubs/scipy/constants.pyi @@ -0,0 +1,7 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +"""IAPWS stubs for scipy.constants""" + +import numpy + +Boltzmann: numpy.Float64 diff --git a/stubs/scipy/optimize.pyi b/stubs/scipy/optimize.pyi new file mode 100644 index 0000000..73aa093 --- /dev/null +++ b/stubs/scipy/optimize.pyi @@ -0,0 +1,40 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +"""IAPWS stubs for scipy.optimize""" + +from typing import Tuple, Dict, Callable, Optional, Literal, Union, Any, overload +import numpy + +# With no full_output option, fsolve returns a numpy.ndarray. +@overload +def fsolve( + func: Callable[..., Any], + x0: Union[float, int, Tuple[Any], Any])-> numpy.ndarray: + ... + +# If someone specified a False full_output option the return value is the same. +@overload +def fsolve( + func: Callable[..., Any], + x0: Union[float, int, Tuple[Any], Any], + full_output: Literal[False])-> numpy.ndarray: + ... + +# With a True full_option, the return value is a different format. +@overload +def fsolve( + func: Callable[..., Any], + x0: Union[float, int, Tuple[Any], Any], + full_output: Literal[True] +) -> Tuple[numpy.ndarray, Dict[str, Any], int, str]: + ... + + +def minimize(fun: Callable[..., Any], x0: Tuple[float], + bounds: Optional[Tuple[Tuple[float, ...]]] = None, + jac: Optional[Callable[..., Any]] = None): + ... + + +def newton(func: Callable[..., Any], x0: float) -> numpy.Float64: + ... diff --git a/stubs/setuptools.pyi b/stubs/setuptools.pyi new file mode 100644 index 0000000..32f829d --- /dev/null +++ b/stubs/setuptools.pyi @@ -0,0 +1,22 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +"""IAPWS stubs for setuptools""" + +from typing import Any, List + +def setup(name: str, + version: Any, + packages: List[str], + include_package_data: bool, + author: str, + author_email: str, + url: str, + download_url: str, + description: str, + long_description: str, + license: str, + python_requires: str, + install_requires: List[str], + classifiers: List[str] +) -> None: + ... From ac491ad6e2b7a2ab20cfec388751cf3ef806761b Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Mon, 15 Mar 2021 14:27:44 -0400 Subject: [PATCH 052/102] Git ignore emacs autosaves. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index f9f520f..2d509c7 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,9 @@ __pycache__/ *.py[cod] +# Emacs autosaves +**/*~ + # C extensions *.so From 1fa0f6bdbd452aedd664a6cb717826fd518a1cc7 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Mon, 15 Mar 2021 14:28:18 -0400 Subject: [PATCH 053/102] Clean up some typing issues in plots.py. Most of the changes were related to reusing variable names with different types. Also correct an earlier type that was forced because of the missing stubs. --- plots.py | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/plots.py b/plots.py index 6f8287c..50f7cff 100755 --- a/plots.py +++ b/plots.py @@ -173,9 +173,9 @@ else: sat = False pts = [] - for p in Pl: + for pressure in Pl: try: - point = fluid(P=p, T=T+273.15) + point = fluid(P=pressure, T=T+273.15) if fluid == iapws.IAPWS97 and not region5 and \ point.region == 5: continue @@ -246,9 +246,9 @@ print(" h=%skJ/kg" % h) H_["%s" % h] = {} pts = [] - for p in Pl: + for pressure in Pl: try: - point = fluid(P=p, h=h) + point = fluid(P=pressure, h=h) if fluid == iapws.IAPWS97 and not region5 and \ point.region == 5: continue @@ -273,9 +273,9 @@ print(" s=%skJ/kgK" % s) S_["%s" % s] = {} pts = [] - for p in Pl: + for pressure in Pl: try: - point = fluid(P=p, s=s) + point = fluid(P=pressure, s=s) if fluid == iapws.IAPWS97 and not region5 and \ point.region == 5: continue @@ -300,10 +300,10 @@ pts95 = [iapws.IAPWS95(T=t, v=v) for t in Tl] x = [] y = [] - for p in pts95: - if p.status: - x.append(p.__getattribute__(xAxis)) - y.append(p.__getattribute__(yAxis)) + for p95 in pts95: + if p95.status: + x.append(p95.__getattribute__(xAxis)) + y.append(p95.__getattribute__(yAxis)) plt.plot(x, y, **isov_kw) @@ -311,19 +311,17 @@ if regionBoundary: # Boundary 1-3 Po = _PSat_T(623.15) - # Mypy was confused about the np.linspace return type. - numpy_pressure_points: List[float] = np.linspace(Po, 100, points) - pts = [fluid(P=p, T=623.15) for p in numpy_pressure_points] + numpy_pressure_points = np.linspace(Po, 100, points) + pts = [fluid(P=float(p), T=623.15) for p in numpy_pressure_points] x = [p.__getattribute__(xAxis) for p in pts] y = [p.__getattribute__(yAxis) for p in pts] plt.plot(x, y, **isosat_kw) # Boundary 2-3 - # Mypy was confused about the np.linspace return type. - numpy_temp_points: List[float] = np.linspace(623.15, 863.15) - Ps = [_P23_T(t) for t in numpy_temp_points] - Ps[-1] = 100 # Avoid round problem with value out of range > 100 MPa - pts = [fluid(P=p, T=t) for p, t in zip(Ps, numpy_temp_points)] + numpy_temp_points = list(map(float, np.linspace(623.15, 863.15))) + Psf = [_P23_T(t) for t in numpy_temp_points] + Psf[-1] = 100.0 # Avoid round problem with value out of range > 100 MPa + pts = [fluid(P=p, T=t) for p, t in zip(Psf, numpy_temp_points)] x = [p.__getattribute__(xAxis) for p in pts] y = [p.__getattribute__(yAxis) for p in pts] plt.plot(x, y, **isosat_kw) From 38d0a95dd12e3fb6924a79b0114dc7f7238749d3 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Mon, 15 Mar 2021 14:31:37 -0400 Subject: [PATCH 054/102] Explicitly convert to Python float from numpy.Float64. --- iapws/iapws08.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/iapws/iapws08.py b/iapws/iapws08.py index 1f48c39..c086b8b 100644 --- a/iapws/iapws08.py +++ b/iapws/iapws08.py @@ -465,7 +465,7 @@ def f(T: float) -> float: return -ps["g"]+S*ps["gs"]-gw+gv Tb = fsolve(f, 300)[0] - return Tb + return float(Tb) def _Tf(P: float, S: float) -> float: @@ -499,7 +499,7 @@ def f(T: float) -> float: return -ps["g"]+S*ps["gs"]-gw+gih Tf = fsolve(f, 300)[0] - return Tf + return float(Tf) def _Triple(S: float) -> Dict[str, float]: @@ -540,8 +540,8 @@ def f(parr: Tuple[float, float]) -> Tuple[float, float]: Tt, Pt = fsolve(f, [273, 6e-4]) prop = {} - prop["Tt"] = Tt - prop["Pt"] = Pt + prop["Tt"] = float(Tt) + prop["Pt"] = float(Pt) return prop @@ -577,7 +577,7 @@ def f(Posm: float) -> float: return -ps["g"]+S*ps["gs"]-gw+gw2 Posm = fsolve(f, 0)[0] - return Posm + return float(Posm) def _ThCond_SeaWater(T: float, P: float, S: float) -> float: From fa1eb5d9208682390b2fad15da1d3c42fbe6ae64 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Mon, 15 Mar 2021 15:41:07 -0400 Subject: [PATCH 055/102] Convert to math.exp() and math.log() where possible. The numpy versions appear to be more permissive, handling domain and range errors as warning messages, while the math versions raise type errors, that are also sometimes detected by mypy. Unfortunately, the remaining places appear to require the numpy versions to pass tests right now. --- iapws/iapws95.py | 53 +++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 9018163..139457e 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -14,10 +14,12 @@ import os import platform import warnings +from math import exp, log +from typing import Tuple, Dict, Optional, List -from numpy import exp, log, ndarray +# Import numpy for a few places still using numpy.log() and numpy.exp() +import numpy from scipy.optimize import fsolve -from typing import Tuple, Dict, Optional, List from .iapws97 import _TSat_P, IAPWS97 from ._iapws import _global_M, Tc, Pc, rhoc, Tc_D2O, Pc_D2O, rhoc_D2O @@ -139,7 +141,7 @@ def _phird(tau: float, delta: float, coef: Dict[str, List[float]]) -> float: t2 = coef.get("t2", []) c2 = coef.get("c2", []) for n, d, g, t, c in zip(nr2, d2, g2, t2, c2): - fird += n*exp(-g*delta**c)*delta**(d-1)*tau**t*(d-g*c*delta**c) + fird += n*numpy.exp(-g*delta**c)*delta**(d-1)*tau**t*(d-g*c*delta**c) # Gaussian terms nr3 = coef.get("nr3", []) @@ -760,9 +762,9 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG - Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) + Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+numpy.log(rhol/rhog)) return (Jl-Jv, - Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, + Jl*(1/rhog-1/rhol)-numpy.log(rhol/rhog)-K, Ps - P*1000) for to in [To, 300, 400, 500, 600]: @@ -930,11 +932,11 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG - Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) + Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+numpy.log(rhol/rhog)) vu = hoG-Ps/rhog lu = hoL-Ps/rhol return (Jl-Jv, - Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, + Jl*(1/rhog-1/rhol)-numpy.log(rhol/rhog)-K, lu*(1-x)+vu*x - u, Ps - P*1000) @@ -994,7 +996,7 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: K = firL-firG x = (1./rho-1/rhol)/(1/rhog-1/rhol) return (Jl-Jv, - Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, + Jl*(1/rhog-1/rhol)-numpy.log(rhol/rhog)-K, hoL*(1-x)+hoG*x - h) for to in [To, 300, 400, 500, 600]: @@ -1059,7 +1061,7 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: K = firL-firG x = (1./rho-1/rhol)/(1/rhog-1/rhol) return (Jl-Jv, - Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, + Jl*(1/rhog-1/rhol)-numpy.log(rhol/rhog)-K, soL*(1-x)+soG*x - s) for to in [To, 300, 400, 500, 600]: @@ -1119,11 +1121,11 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: Jv = rhog*(1+deltaG*firdG) K = firL-firG x = (1./rho-1/rhol)/(1/rhog-1/rhol) - Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) + Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+numpy.log(rhol/rhog)) vu = hoG-Ps/rhog lu = hoL-Ps/rhol return (Jl-Jv, - Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, + Jl*(1/rhog-1/rhol)-numpy.log(rhol/rhog)-K, lu*(1-x)+vu*x - u) for to in [To, 300, 400, 500, 600]: @@ -1335,12 +1337,12 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ Jv = rhog*(1+deltaG*firdG) K = firL-firG - Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) + Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+numpy.log(rhol/rhog)) vu = hoG-Ps/rhog lu = hoL-Ps/rhol return (Jl-Jv, - Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, + Jl*(1/rhog-1/rhol)-numpy.log(rhol/rhog)-K, soL*(1-x)+soG*x - s, lu*(1-x)+vu*x - u) @@ -1685,10 +1687,6 @@ def _Helmholtz(self, rho: float, T: float) -> Dict[str, float]: Scientific Use, September 2016, Table 3 http://www.iapws.org/relguide/IAPWS-95.html """ - if isinstance(rho, ndarray): - rho = rho[0] - if isinstance(T, ndarray): - T = T[0] if rho < 0: rho = 1e-20 if T < 50: @@ -1775,7 +1773,7 @@ def _phi0(self, tau: float, delta: float) -> Dict[str, float]: """ Fi0 = self.Fi0 - fio = Fi0["ao_log"][0]*log(delta)+Fi0["ao_log"][1]*log(tau) + fio = Fi0["ao_log"][0]*numpy.log(delta)+Fi0["ao_log"][1]*numpy.log(tau) fiot = +Fi0["ao_log"][1]/tau fiott = -Fi0["ao_log"][1]/tau**2 @@ -1791,9 +1789,9 @@ def _phi0(self, tau: float, delta: float) -> Dict[str, float]: fiott += n*t*(t-1)*tau**(t-2) for n, t in zip(Fi0["ao_exp"], Fi0["titao"]): - fio += n*log(1-exp(-tau*t)) - fiot += n*t*((1-exp(-t*tau))**-1-1) - fiott -= n*t**2*exp(-t*tau)*(1-exp(-t*tau))**-2 + fio += n*numpy.log(1-numpy.exp(-tau*t)) + fiot += n*t*((1-numpy.exp(-t*tau))**-1-1) + fiott -= n*t**2*numpy.exp(-t*tau)*(1-numpy.exp(-t*tau))**-2 # Extension to especial terms of air if "ao_exp2" in Fi0: @@ -1860,14 +1858,13 @@ def _phir(self, tau: float, delta: float) -> Dict[str, float]: t2 = self._constants.get("t2", []) c2 = self._constants.get("c2", []) for n, d, g, t, c in zip(nr2, d2, g2, t2, c2): - fir += n*delta**d*tau**t*exp(-g*delta**c) - fird += n*exp(-g*delta**c)*delta**(d-1)*tau**t*(d-g*c*delta**c) - firdd += n*exp(-g*delta**c)*delta**(d-2)*tau**t * \ + fir += n*delta**d*tau**t*numpy.exp(-g*delta**c) + fird += n*numpy.exp(-g*delta**c)*delta**(d-1)*tau**t*(d-g*c*delta**c) + firdd += n*numpy.exp(-g*delta**c)*delta**(d-2)*tau**t * \ ((d-g*c*delta**c)*(d-1-g*c*delta**c)-g**2*c**2*delta**c) - firt += n*t*delta**d*tau**(t-1)*exp(-g*delta**c) - firtt += n*t*(t-1)*delta**d*tau**(t-2)*exp(-g*delta**c) - firdt += n*t*delta**(d-1)*tau**(t-1)*(d-g*c*delta**c)*exp( - -g*delta**c) + firt += n*t*delta**d*tau**(t-1)*numpy.exp(-g*delta**c) + firtt += n*t*(t-1)*delta**d*tau**(t-2)*numpy.exp(-g*delta**c) + firdt += n*t*delta**(d-1)*tau**(t-1)*(d-g*c*delta**c)*numpy.exp(-g*delta**c) # Gaussian terms nr3 = self._constants.get("nr3", []) From cb544ab92d79447a635c1e56a649040cf1d51ecc Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Mon, 15 Mar 2021 16:00:06 -0400 Subject: [PATCH 056/102] Isolate numpy.log() and numpy.exp() calls as much as possible. While minimizing other changes, this commit reduces the number of calls to each numpy method, and makes it more obvious where the domain errors are. --- iapws/iapws95.py | 59 ++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 139457e..4ed0374 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -762,10 +762,9 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG - Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+numpy.log(rhol/rhog)) - return (Jl-Jv, - Jl*(1/rhog-1/rhol)-numpy.log(rhol/rhog)-K, - Ps - P*1000) + logrho = numpy.log(rhol/rhog) + Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+logrho) + return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, Ps - P*1000) for to in [To, 300, 400, 500, 600]: rhoLo = self._Liquid_Density(to) @@ -932,13 +931,12 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG - Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+numpy.log(rhol/rhog)) + logrho = numpy.log(rhol/rhog) + Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+logrho) vu = hoG-Ps/rhog lu = hoL-Ps/rhol - return (Jl-Jv, - Jl*(1/rhog-1/rhol)-numpy.log(rhol/rhog)-K, - lu*(1-x)+vu*x - u, - Ps - P*1000) + return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, + lu*(1-x)+vu*x - u, Ps - P*1000) for to in [To, 300, 400, 500, 600]: rLo = self._Liquid_Density(to) @@ -995,8 +993,8 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: Jv = rhog*(1+deltaG*firdG) K = firL-firG x = (1./rho-1/rhol)/(1/rhog-1/rhol) - return (Jl-Jv, - Jl*(1/rhog-1/rhol)-numpy.log(rhol/rhog)-K, + logrho = numpy.log(rhol/rhog) + return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, hoL*(1-x)+hoG*x - h) for to in [To, 300, 400, 500, 600]: @@ -1060,8 +1058,8 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: Jv = rhog*(1+deltaG*firdG) K = firL-firG x = (1./rho-1/rhol)/(1/rhog-1/rhol) - return (Jl-Jv, - Jl*(1/rhog-1/rhol)-numpy.log(rhol/rhog)-K, + logrho = numpy.log(rhol/rhog) + return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, soL*(1-x)+soG*x - s) for to in [To, 300, 400, 500, 600]: @@ -1121,11 +1119,11 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: Jv = rhog*(1+deltaG*firdG) K = firL-firG x = (1./rho-1/rhol)/(1/rhog-1/rhol) - Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+numpy.log(rhol/rhog)) + logrho = numpy.log(rhol/rhog) + Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+logrho) vu = hoG-Ps/rhog lu = hoL-Ps/rhol - return (Jl-Jv, - Jl*(1/rhog-1/rhol)-numpy.log(rhol/rhog)-K, + return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, lu*(1-x)+vu*x - u) for to in [To, 300, 400, 500, 600]: @@ -1337,14 +1335,13 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ Jv = rhog*(1+deltaG*firdG) K = firL-firG - Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+numpy.log(rhol/rhog)) + logrho = numpy.log(rhol/rhog) + Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+logrho) vu = hoG-Ps/rhog lu = hoL-Ps/rhol - return (Jl-Jv, - Jl*(1/rhog-1/rhol)-numpy.log(rhol/rhog)-K, - soL*(1-x)+soG*x - s, - lu*(1-x)+vu*x - u) + return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, + soL*(1-x)+soG*x - s, lu*(1-x)+vu*x - u) for to in [To, 300, 400, 500, 600]: rLo = self._Liquid_Density(to) @@ -1789,9 +1786,10 @@ def _phi0(self, tau: float, delta: float) -> Dict[str, float]: fiott += n*t*(t-1)*tau**(t-2) for n, t in zip(Fi0["ao_exp"], Fi0["titao"]): - fio += n*numpy.log(1-numpy.exp(-tau*t)) - fiot += n*t*((1-numpy.exp(-t*tau))**-1-1) - fiott -= n*t**2*numpy.exp(-t*tau)*(1-numpy.exp(-t*tau))**-2 + expt = numpy.exp(-t*tau) + fio += n*numpy.log(1-expt) + fiot += n*t*((1-expt)**-1-1) + fiott -= n*t**2*expt*(1-expt)**-2 # Extension to especial terms of air if "ao_exp2" in Fi0: @@ -1858,13 +1856,14 @@ def _phir(self, tau: float, delta: float) -> Dict[str, float]: t2 = self._constants.get("t2", []) c2 = self._constants.get("c2", []) for n, d, g, t, c in zip(nr2, d2, g2, t2, c2): - fir += n*delta**d*tau**t*numpy.exp(-g*delta**c) - fird += n*numpy.exp(-g*delta**c)*delta**(d-1)*tau**t*(d-g*c*delta**c) - firdd += n*numpy.exp(-g*delta**c)*delta**(d-2)*tau**t * \ + expgdc = numpy.exp(-g*delta**c) + fir += n*delta**d*tau**t*expgdc + fird += n*expgdc*delta**(d-1)*tau**t*(d-g*c*delta**c) + firdd += n*expgdc*delta**(d-2)*tau**t * \ ((d-g*c*delta**c)*(d-1-g*c*delta**c)-g**2*c**2*delta**c) - firt += n*t*delta**d*tau**(t-1)*numpy.exp(-g*delta**c) - firtt += n*t*(t-1)*delta**d*tau**(t-2)*numpy.exp(-g*delta**c) - firdt += n*t*delta**(d-1)*tau**(t-1)*(d-g*c*delta**c)*numpy.exp(-g*delta**c) + firt += n*t*delta**d*tau**(t-1)*expgdc + firtt += n*t*(t-1)*delta**d*tau**(t-2)*expgdc + firdt += n*t*delta**(d-1)*tau**(t-1)*(d-g*c*delta**c)*expgdc # Gaussian terms nr3 = self._constants.get("nr3", []) From aaeca01a8de98747759070b37d51d0e2788c3511 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Mon, 15 Mar 2021 19:41:16 -0400 Subject: [PATCH 057/102] A working version with no numpy log()/exp() dependency. Using numpy.seterr('raise') would raise exceptions, those exceptions are now more clearly marked in the code with actualy try/except blocks, which can be revisited in the future to see if (and why) they're truly needed. --- iapws/humidAir.py | 3 ++ iapws/iapws95.py | 99 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 86 insertions(+), 16 deletions(-) diff --git a/iapws/humidAir.py b/iapws/humidAir.py index 2450dc0..445ec3b 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -353,6 +353,9 @@ def _Liquid_Density(cls, T: float) -> float: rho : float Saturated liquid density [kg/m³] """ + # Convert numpy.Float64 back into Python floats. + T = float(T) + Tc = 132.6312 rhoc = 10.4477*cls.M Ni = [44.3413, -240.073, 285.139, -88.3366] diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 4ed0374..7d6e0af 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -9,7 +9,6 @@ * :class:`D2O`: 2017 formulation for heavy water. """ - from __future__ import division import os import platform @@ -17,8 +16,6 @@ from math import exp, log from typing import Tuple, Dict, Optional, List -# Import numpy for a few places still using numpy.log() and numpy.exp() -import numpy from scipy.optimize import fsolve from .iapws97 import _TSat_P, IAPWS97 @@ -54,6 +51,10 @@ def _phir(tau: float, delta: float, coef: Dict[str, List[float]]) -> float: """ fir = 0.0 + # Convert numpy.Float64 back into Python floats. + tau = float(tau) + delta = float(delta) + # Polinomial terms nr1 = coef.get("nr1", []) d1 = coef.get("d1", []) @@ -127,6 +128,10 @@ def _phird(tau: float, delta: float, coef: Dict[str, List[float]]) -> float: """ fird = 0.0 + # Convert numpy.Float64 back into Python floats. + tau = float(tau) + delta = float(delta) + # Polinomial terms nr1 = coef.get("nr1", []) d1 = coef.get("d1", []) @@ -141,7 +146,12 @@ def _phird(tau: float, delta: float, coef: Dict[str, List[float]]) -> float: t2 = coef.get("t2", []) c2 = coef.get("c2", []) for n, d, g, t, c in zip(nr2, d2, g2, t2, c2): - fird += n*numpy.exp(-g*delta**c)*delta**(d-1)*tau**t*(d-g*c*delta**c) + try: + expt = exp(-g*delta**c) + except OverflowError: + fird = float('nan') + break + fird += n*expt*delta**(d-1)*tau**t*(d-g*c*delta**c) # Gaussian terms nr3 = coef.get("nr3", []) @@ -152,8 +162,8 @@ def _phird(tau: float, delta: float, coef: Dict[str, List[float]]) -> float: b3 = coef.get("beta3", []) g3 = coef.get("gamma3", []) for n, d, t, a, e, b, g in zip(nr3, d3, t3, a3, e3, b3, g3): - fird += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - d/delta-2*a*(delta-e)) + expt = exp(-a*(delta-e)**2-b*(tau-g)**2) + fird += n*delta**d*tau**t*expt*(d/delta-2*a*(delta-e)) # Non analitic terms nr4 = coef.get("nr4", []) @@ -207,6 +217,10 @@ def _phirt(tau: float, delta: float, coef: Dict[str, List[float]]) -> float: """ firt = 0.0 + # Convert numpy.Float64 back into Python floats. + tau = float(tau) + delta = float(delta) + # Polinomial terms nr1 = coef.get("nr1", []) d1 = coef.get("d1", []) @@ -762,7 +776,10 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG - logrho = numpy.log(rhol/rhog) + try: + logrho = log(rhol/rhog) + except ValueError: + logrho = float('nan') Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+logrho) return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, Ps - P*1000) @@ -931,7 +948,10 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) K = firL-firG - logrho = numpy.log(rhol/rhog) + try: + logrho = log(rhol/rhog) + except ValueError: + logrho = float('nan') Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+logrho) vu = hoG-Ps/rhog lu = hoL-Ps/rhol @@ -993,7 +1013,10 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: Jv = rhog*(1+deltaG*firdG) K = firL-firG x = (1./rho-1/rhol)/(1/rhog-1/rhol) - logrho = numpy.log(rhol/rhog) + try: + logrho = log(rhol/rhog) + except ValueError: + logrho = float('nan') return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, hoL*(1-x)+hoG*x - h) @@ -1058,7 +1081,10 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: Jv = rhog*(1+deltaG*firdG) K = firL-firG x = (1./rho-1/rhol)/(1/rhog-1/rhol) - logrho = numpy.log(rhol/rhog) + try: + logrho = log(rhol/rhog) + except ValueError: + logrho = float('nan') return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, soL*(1-x)+soG*x - s) @@ -1119,7 +1145,10 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: Jv = rhog*(1+deltaG*firdG) K = firL-firG x = (1./rho-1/rhol)/(1/rhog-1/rhol) - logrho = numpy.log(rhol/rhog) + try: + logrho = log(rhol/rhog) + except ValueError: + logrho = float('nan') Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+logrho) vu = hoG-Ps/rhog lu = hoL-Ps/rhol @@ -1335,7 +1364,10 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ Jv = rhog*(1+deltaG*firdG) K = firL-firG - logrho = numpy.log(rhol/rhog) + try: + logrho = log(rhol/rhog) + except ValueError: + logrho = float('nan') Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+logrho) vu = hoG-Ps/rhog lu = hoL-Ps/rhol @@ -1770,7 +1802,17 @@ def _phi0(self, tau: float, delta: float) -> Dict[str, float]: """ Fi0 = self.Fi0 - fio = Fi0["ao_log"][0]*numpy.log(delta)+Fi0["ao_log"][1]*numpy.log(tau) + try: + dlog = log(delta) + except ValueError: + dlog = float('nan') + + try: + tlog = log(tau) + except ValueError: + tlog = float('nan') + + fio = Fi0["ao_log"][0]*dlog+Fi0["ao_log"][1]*tlog fiot = +Fi0["ao_log"][1]/tau fiott = -Fi0["ao_log"][1]/tau**2 @@ -1786,8 +1828,15 @@ def _phi0(self, tau: float, delta: float) -> Dict[str, float]: fiott += n*t*(t-1)*tau**(t-2) for n, t in zip(Fi0["ao_exp"], Fi0["titao"]): - expt = numpy.exp(-t*tau) - fio += n*numpy.log(1-expt) + try: + expt = exp(-t*tau) + except OverflowError: + expt = float('inf') + try: + logterm = log(1-expt) + except ValueError: + logterm = float('nan') + fio += n*logterm fiot += n*t*((1-expt)**-1-1) fiott -= n*t**2*expt*(1-expt)**-2 @@ -1837,6 +1886,10 @@ def _phir(self, tau: float, delta: float) -> Dict[str, float]: """ fir = fird = firdd = firt = firtt = firdt = 0.0 + # Convert numpy.Float64 back into Python floats. + tau = float(tau) + delta = float(delta) + # Polinomial terms nr1 = self._constants.get("nr1", []) d1 = self._constants.get("d1", []) @@ -1855,8 +1908,13 @@ def _phir(self, tau: float, delta: float) -> Dict[str, float]: g2 = self._constants.get("gamma2", []) t2 = self._constants.get("t2", []) c2 = self._constants.get("c2", []) + failed = False for n, d, g, t, c in zip(nr2, d2, g2, t2, c2): - expgdc = numpy.exp(-g*delta**c) + try: + expgdc = exp(-g*delta**c) + except OverflowError: + failed = True + expgdc = float('inf') fir += n*delta**d*tau**t*expgdc fird += n*expgdc*delta**(d-1)*tau**t*(d-g*c*delta**c) firdd += n*expgdc*delta**(d-2)*tau**t * \ @@ -1864,6 +1922,8 @@ def _phir(self, tau: float, delta: float) -> Dict[str, float]: firt += n*t*delta**d*tau**(t-1)*expgdc firtt += n*t*(t-1)*delta**d*tau**(t-2)*expgdc firdt += n*t*delta**(d-1)*tau**(t-1)*(d-g*c*delta**c)*expgdc + if failed: + fir = float('nan') # Gaussian terms nr3 = self._constants.get("nr3", []) @@ -2172,6 +2232,8 @@ def _Liquid_Density(cls, T: float) -> float: Ordinary Water Substance September 1992, http://www.iapws.org/relguide/Supp-sat.html, Eq.2 """ + # Convert numpy.Float64 back into Python floats. + T = float(T) Tita = 1-T/cls.Tc if cls._rhoL_eq == 2: Tita = Tita**(1./3) @@ -2202,12 +2264,17 @@ def _Vapor_Density(cls, T: float) -> float: Ordinary Water Substance September 1992, http://www.iapws.org/relguide/Supp-sat.html, Eq.3 """ + # Convert numpy.Float64 back into Python floats. + T = float(T) Tita = 1-T/cls.Tc if cls._rhoG_eq == 4: Tita = Tita**(1./3) suma = 0.0 for n, x in zip(cls._rhoG_ao, cls._rhoG_exp): suma += n*Tita**x + if type(suma) == complex: + suma = float('nan') + Pr = exp(suma) rho = Pr*cls.rhoc return rho From f9abf87a9a3cddc4368cd5344cebe932a3460aa5 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Mon, 15 Mar 2021 20:06:09 -0400 Subject: [PATCH 058/102] More comprehensively cast from numpy.Float64 to Python float. Since fsolve, newton, and minimize are the primary (only?) internal sources of the numpy types, I think this means we're really and truly using Python floats throughout the code now. That means that I should be able to eliminate numpy type confusion as the causes of the remaing mypy errors. --- iapws/_iapws.py | 5 ++-- iapws/humidAir.py | 7 +++--- iapws/iapws95.py | 58 +++++++++++++++++++++++------------------------ iapws/iapws97.py | 36 ++++++++++++++--------------- 4 files changed, 53 insertions(+), 53 deletions(-) diff --git a/iapws/_iapws.py b/iapws/_iapws.py index bc4e3bd..2fe0d70 100644 --- a/iapws/_iapws.py +++ b/iapws/_iapws.py @@ -407,8 +407,9 @@ def jac(self, x: float) -> float: @property def x(self) -> float: - return minimize(self.f, x0=((self.xmin+self.xmax)/2,), - bounds=((self.xmin, self.xmax),), jac=self.jac)["x"][0] + m = minimize(self.f, x0=((self.xmin+self.xmax)/2,), + bounds=((self.xmin, self.xmax),), jac=self.jac)["x"][0] + return float(m) # IAPWS-15 for supercooled liquid water diff --git a/iapws/humidAir.py b/iapws/humidAir.py index 445ec3b..966cfdb 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -661,12 +661,12 @@ def calculo(self) -> None: def rho_func(rhopar: float) -> float: fav = self._fav(T, rhopar, A) return rhopar**2*fav["fird"]/1000-P - rho = fsolve(rho_func, 1)[0] + rho = float(fsolve(rho_func, 1)[0]) elif self._mode == "Prho": def t_func(Tpar: float) -> float: fav = self._fav(Tpar, rho, A) return rho**2*fav["fird"]/1000-P - T = fsolve(t_func, 300)[0] + T = float(fsolve(t_func, 300)[0]) assert(T is not None) assert(isinstance(rho, float)) @@ -746,8 +746,7 @@ def f(parr: Tuple[float, float]) -> Tuple[float, float]: muw = fa["fir"]+rho*fa["fird"]-a*fa["fira"] return gw-muw, rho**2*fa["fird"]/1000-P - rinput = fsolve(f, [1, 0.95], full_output=True) - Asat = rinput[0][1] + Asat = float(fsolve(f, [1, 0.95], full_output=True)[0][1]) return Asat def _prop(self, T: float, rho: float, fav: Dict[str, float]) -> Dict[str, float]: diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 7d6e0af..857339b 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -583,7 +583,7 @@ def rho_func(rho: float) -> float: Po = (1+delta*fird)*self.R*T*rho return Po-P*1000 - rho = fsolve(rho_func, rhoo)[0] + rho = float(fsolve(rho_func, rhoo)[0]) # Calculate quality if T > self.Tc: @@ -613,7 +613,7 @@ def rho_func(rho: float) -> float: if T >= self.Tc: rhoo = self.rhoc - rho = fsolve(rho_func, rhoo)[0] + rho = float(fsolve(rho_func, rhoo)[0]) else: x0 = self.kwargs["x0"] rhov = self._Vapor_Density(T) @@ -641,7 +641,7 @@ def rho_func(rho: float) -> float: rhoo = rhov else: rhoo = rhol - rho = fsolve(rho_func, rhoo)[0] + rho = float(fsolve(rho_func, rhoo)[0]) elif self._mode == "Ts": tau = Tc/T @@ -661,7 +661,7 @@ def rho_func(rho: float) -> float: if T >= self.Tc: rhoo = self.rhoc - rho = fsolve(rho_func, rhoo)[0] + rho = float(fsolve(rho_func, rhoo)[0]) else: rhov = self._Vapor_Density(T) rhol = self._Liquid_Density(T) @@ -694,7 +694,7 @@ def rho_func(rho: float) -> float: rhoo = rhov else: rhoo = rhol - rho = fsolve(rho_func, rhoo)[0] + rho = float(fsolve(rho_func, rhoo)[0]) elif self._mode == "Tu": tau = Tc/T @@ -713,7 +713,7 @@ def rho_func(rho: float) -> float: if T >= self.Tc: rhoo = self.rhoc - rho = fsolve(rho_func, rhoo)[0] + rho = float(fsolve(rho_func, rhoo)[0]) else: rhov = self._Vapor_Density(T) rhol = self._Liquid_Density(T) @@ -745,7 +745,7 @@ def rho_func(rho: float) -> float: rhoo = rhov else: rhoo = rhol - rho = fsolve(rho_func, rhoo)[0] + rho = float(fsolve(rho_func, rhoo)[0]) elif self._mode == "Prho": delta = rho/rhoc @@ -757,7 +757,7 @@ def t_func(T: float) -> float: Po = (1+delta*fird)*self.R*T*rho return Po-P*1000 - T = fsolve(t_func, To)[0] + T = float(fsolve(t_func, To)[0]) rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if T == To or rhov <= rho <= rhol: @@ -787,7 +787,7 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: rhoLo = self._Liquid_Density(to) rhoGo = self._Vapor_Density(to) sol = fsolve(f3, [to, rhoLo, rhoGo], full_output=True) - T, rhoL, rhoG = sol[0] + T, rhoL, rhoG = tuple(map(float, sol[0])) x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: @@ -815,7 +815,7 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return Po-P*1000, ho-h - rho, T = fsolve(f2, [rhoo, To]) + rho, T = tuple(map(float, fsolve(f2, [rhoo, To]))) rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if rho == rhoo or rhov <= rho <= rhol: @@ -853,7 +853,7 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ rLo = self._Liquid_Density(to) rGo = self._Vapor_Density(to) sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) - T, rhoL, rhoG, x = sol[0] + T, rhoL, rhoG, x = tuple(map(float, sol[0])) if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: break @@ -888,7 +888,7 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: so = self.R*(tau*(fiot+firt)-fio-fir) return Po-P*1000, so-s - rho, T = fsolve(f2, [rhoo, To]) + rho, T = tuple(map(float, fsolve(f2, [rhoo, To]))) else: def f2(parr: Tuple[float, float]) -> Tuple[float, float]: @@ -898,7 +898,7 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: liquido = self._Helmholtz(rhol, T) x = (1./rho-1/rhol)/(1/rhov-1/rhol) return Ps-P*1000, vapor["s"]*x+liquido["s"]*(1-x)-s - rho, T = fsolve(f2, [2., 500.]) + rho, T = tuple(map(float, fsolve(f2, [2., 500.]))) rhol, rhov, Ps = self._saturation(T) vapor = self._Helmholtz(rhov, T) liquido = self._Helmholtz(rhol, T) @@ -921,7 +921,7 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: return ho-Po/rho-u, Po-P*1000 sol = fsolve(f2, [rhoo, To], full_output=True) - rho, T = sol[0] + rho, T = tuple(map(float, sol[0])) rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if rho == rhoo or sol[2] != 1: @@ -962,7 +962,7 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ rLo = self._Liquid_Density(to) rGo = self._Vapor_Density(to) sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) - T, rhoL, rhoG, x = sol[0] + T, rhoL, rhoG, x = tuple(map(float, sol[0])) if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: break @@ -988,7 +988,7 @@ def t_func(T: float) -> float: ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return ho-h - T = fsolve(t_func, To)[0] + T = float(fsolve(t_func, To)[0]) rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if T == To or rhov <= rho <= rhol: @@ -1024,7 +1024,7 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: rhoLo = self._Liquid_Density(to) rhoGo = self._Vapor_Density(to) sol = fsolve(f3, [to, rhoLo, rhoGo], full_output=True) - T, rhoL, rhoG = sol[0] + T, rhoL, rhoG = tuple(map(float, sol[0])) x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: @@ -1051,7 +1051,7 @@ def t_func(T: float) -> float: so = self.R*(tau*(fiot+firt)-fio-fir) return so-s - T = fsolve(t_func, To)[0] + T = float(fsolve(t_func, To)[0]) rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if T == To or rhov <= rho <= rhol: @@ -1092,7 +1092,7 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: rhoLo = self._Liquid_Density(to) rhoGo = self._Vapor_Density(to) sol = fsolve(f3, [to, rhoLo, rhoGo], full_output=True) - T, rhoL, rhoG = sol[0] + T, rhoL, rhoG = tuple(map(float, sol[0])) x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: @@ -1120,7 +1120,7 @@ def t_func(T: float) -> float: ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return ho-Po/rho-u - T = fsolve(t_func, To)[0] + T = float(fsolve(t_func, To)[0]) rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if T == To or rhov <= rho <= rhol: @@ -1159,7 +1159,7 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: rhoLo = self._Liquid_Density(to) rhoGo = self._Vapor_Density(to) sol = fsolve(f3, [to, rhoLo, rhoGo], full_output=True) - T, rhoL, rhoG = sol[0] + T, rhoL, rhoG = tuple(map(float, sol[0])) x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: @@ -1189,7 +1189,7 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: so = self.R*(tau*(fiot+firt)-fio-fir) return ho-h, so-s - rho, T = fsolve(f2, [rhoo, To]) + rho, T = tuple(map(float, fsolve(f2, [rhoo, To]))) rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if rhov <= rho <= rhol: @@ -1230,7 +1230,7 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ rLo = self._Liquid_Density(to) rGo = self._Vapor_Density(to) sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) - T, rhoL, rhoG, x = sol[0] + T, rhoL, rhoG, x = tuple(map(float, sol[0])) if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: break @@ -1259,7 +1259,7 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: return ho-Po/rho-u, ho-h sol = fsolve(f2, [rhoo, To], full_output=True) - rho, T = sol[0] + rho, T = tuple(map(float, sol[0])) rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if sol[2] != 1 or rhov <= rho <= rhol: @@ -1300,7 +1300,7 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ rLo = self._Liquid_Density(to) rGo = self._Vapor_Density(to) sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) - T, rhoL, rhoG, x = sol[0] + T, rhoL, rhoG, x = tuple(map(float, sol[0])) if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: break @@ -1331,7 +1331,7 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: return ho-Po/rho-u, so-s sol = fsolve(f2, [rhoo, To], full_output=True) - rho, T = sol[0] + rho, T = tuple(map(float, sol[0])) rhol = self._Liquid_Density(T) rhov = self._Vapor_Density(T) if sol[2] != 1 or rhov <= rho <= rhol: @@ -1379,7 +1379,7 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ rLo = self._Liquid_Density(to) rGo = self._Vapor_Density(to) sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) - T, rhoL, rhoG, x = sol[0] + T, rhoL, rhoG, x = tuple(map(float, sol[0])) if sol[2] == 1 and 0 <= x <= 1 and \ sum(abs(sol[1]["fvec"])) < 1e-5: break @@ -1457,7 +1457,7 @@ def t_func(T: float) -> float: To = _TSat_P(P) else: To = (self.Tc+self.Tt)/2 - T = fsolve(t_func, To)[0] + T = float(fsolve(t_func, To)[0]) rhol, rhov, Ps = self._saturation(T) vapor = self._Helmholtz(rhov, T) liquido = self._Helmholtz(rhol, T) @@ -1672,7 +1672,7 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: Kv = deltaG*phirdG+phirG+log(deltaG) return Kv-Kl, Jv-Jl - rhoL, rhoG = fsolve(f2, [rhoLo, rhoGo]) + rhoL, rhoG = tuple(map(float, fsolve(f2, [rhoLo, rhoGo]))) if rhoL == rhoG: Ps = self.Pc else: diff --git a/iapws/iapws97.py b/iapws/iapws97.py index c593d91..426fcb2 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -4166,7 +4166,7 @@ def _Bound_hs(h: float, s: float) -> Optional[int]: def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return (_Region5(par[0], par[1])["h"]-h, _Region5(par[0], par[1])["s"]-s) - T, P = fsolve(funcion, [1400, 1]) + T, P = tuple(map(float, fsolve(funcion, [1400, 1]))) if 1073.15 < T <= 2273.15 and Pmin <= P <= 50: region = 5 @@ -4385,7 +4385,7 @@ def calculo(self): def rho_funcion(rho: float) -> float: return _Region3(rho, self.kwargs["T"])["P"]-P - rho = newton(rho_funcion, 1/vo) + rho = float(newton(rho_funcion, 1/vo)) propiedades = _Region3(rho, T) elif region == 5: propiedades = _Region5(T, P) @@ -4397,11 +4397,11 @@ def rho_funcion(rho: float) -> float: region = _Bound_Ph(P, h) if region == 1: To = _Backward1_T_Ph(P, h) - T = newton(lambda T: _Region1(T, P)["h"]-h, To) + T = float(newton(lambda T: _Region1(T, P)["h"]-h, To)) propiedades = _Region1(T, P) elif region == 2: To = _Backward2_T_Ph(P, h) - T = newton(lambda T: _Region2(T, P)["h"]-h, To) + T = float(newton(lambda T: _Region2(T, P)["h"]-h, To)) propiedades = _Region2(T, P) elif region == 3: vo = _Backward3_v_Ph(P, h) @@ -4410,7 +4410,7 @@ def rho_funcion(rho: float) -> float: def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return (_Region3(par[0], par[1])["h"]-h, _Region3(par[0], par[1])["P"]-P) - rho, T = fsolve(funcion, [1/vo, To]) + rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) propiedades = _Region3(rho, T) elif region == 4: T = _TSat_P(P) @@ -4426,10 +4426,10 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return (_Region3(par[0], par[1])["h"]-h, _Region3(par[0], par[1])["P"]-P) - rho, T = fsolve(funcion, [1/vo, To]) + rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) propiedades = _Region3(rho, T) elif region == 5: - T = newton(lambda T: _Region5(T, P)["h"]-h, 1500) + T = float(newton(lambda T: _Region5(T, P)["h"]-h, 1500)) propiedades = _Region5(T, P) else: raise NotImplementedError("Incoming out of bound") @@ -4439,11 +4439,11 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: region = _Bound_Ps(P, s) if region == 1: To = _Backward1_T_Ps(P, s) - T = newton(lambda T: _Region1(T, P)["s"]-s, To) + T = float(newton(lambda T: _Region1(T, P)["s"]-s, To)) propiedades = _Region1(T, P) elif region == 2: To = _Backward2_T_Ps(P, s) - T = newton(lambda T: _Region2(T, P)["s"]-s, To) + T = float(newton(lambda T: _Region2(T, P)["s"]-s, To)) propiedades = _Region2(T, P) elif region == 3: vo = _Backward3_v_Ps(P, s) @@ -4452,7 +4452,7 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return (_Region3(par[0], par[1])["s"]-s, _Region3(par[0], par[1])["P"]-P) - rho, T = fsolve(funcion, [1/vo, To]) + rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) propiedades = _Region3(rho, T) elif region == 4: T = _TSat_P(P) @@ -4468,10 +4468,10 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return (_Region3(par[0], par[1])["s"]-s, _Region3(par[0], par[1])["P"]-P) - rho, T = fsolve(funcion, [1/vo, To]) + rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) propiedades = _Region3(rho, T) elif region == 5: - T = newton(lambda T: _Region5(T, P)["s"]-s, 1500) + T = float(newton(lambda T: _Region5(T, P)["s"]-s, 1500)) propiedades = _Region5(T, P) else: raise NotImplementedError("Incoming out of bound") @@ -4486,7 +4486,7 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return (_Region1(par[0], par[1])["h"]-h, _Region1(par[0], par[1])["s"]-s) - T, P = fsolve(funcion, [To, Po]) + T, P = tuple(map(float, fsolve(funcion, [To, Po]))) propiedades = _Region1(T, P) elif region == 2: Po = _Backward2_P_hs(h, s) @@ -4495,7 +4495,7 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return (_Region2(par[0], par[1])["h"]-h, _Region2(par[0], par[1])["s"]-s) - T, P = fsolve(funcion, [To, Po]) + T, P = tuple(map(float, fsolve(funcion, [To, Po]))) propiedades = _Region2(T, P) elif region == 3: P = _Backward3_P_hs(h, s) @@ -4505,7 +4505,7 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return (_Region3(par[0], par[1])["h"]-h, _Region3(par[0], par[1])["s"]-s) - rho, T = fsolve(funcion, [1/vo, To]) + rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) propiedades = _Region3(rho, T) elif region == 4: if round(s-sc, 6) == 0 and round(h-hc, 6) == 0: @@ -4548,7 +4548,7 @@ def funcion2(par: List[float]) -> Tuple[float, float]: sv = vapor["s"] return (hv*pp1+hl*(1-pp1)-h, sv*pp1+sl*(1-pp1)-s) - T, x = fsolve(funcion2, [To, 0.5]) + T, x = tuple(map(float, fsolve(funcion2, [To, 0.5]))) P = _PSat_T(T) if Pt <= P < Pc and 0 < x < 1: @@ -4559,7 +4559,7 @@ def funcion2(par: List[float]) -> Tuple[float, float]: def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return (_Region5(par[0], par[1])["h"]-h, _Region5(par[0], par[1])["s"]-s) - T, P = fsolve(funcion, [1400, 1]) + T, P = tuple(map(float, fsolve(funcion, [1400, 1]))) propiedades = _Region5(T, P) else: raise NotImplementedError("Incoming out of bound") @@ -4577,7 +4577,7 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: def rho_funcion(rho: float) -> float: return _Region3(rho, T)["P"]-P rhoo = 1./_Backward3_sat_v_P(P, T, x) - rho = fsolve(rho_funcion, rhoo)[0] + rho = float(fsolve(rho_funcion, rhoo)[0]) propiedades = _Region3(rho, T) elif P == Pc and 0 <= x <= 1: propiedades = _Region3(rhoc, Tc) From b05ee95e50d36b6900f9455093d51c099460edd1 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Mon, 15 Mar 2021 20:21:57 -0400 Subject: [PATCH 059/102] This commit demonstrates that numpy.Float64 is mostly gone. It's not that I dislike numpy.Float64 some much as there is no good static typing information for the numpy module, so it's hard to tell if numpy code does what it seems to. :-( Plus now when we say a method returns a float, we really mean that, and not just a somewhat float-like Python object backed by a C extension. --- iapws/ammonia.py | 3 ++- plots.py | 12 ++++++++---- stubs/numpy/__init__.pyi | 11 ++++++++--- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/iapws/ammonia.py b/iapws/ammonia.py index c074d75..1c6471b 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -184,7 +184,8 @@ def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> Optiona dPT = 1e5*(2.18-0.12/exp(17.8*t)) nbx = 1e-5*(2.6+1.6*t) - DL = 1.2*Boltzmann*T**2/6/pi/nbx/(1.34e-10/t**0.63*(1+t**0.5))*dPT**2 * \ + kb = float(Boltzmann) + DL = 1.2*kb*T**2/6/pi/nbx/(1.34e-10/t**0.63*(1+t**0.5))*dPT**2 * \ 0.423e-8/t**1.24*(1+t**0.5/0.7) # Add correction for entire range of temperature, Eq 10 diff --git a/plots.py b/plots.py index 50f7cff..2b79bac 100755 --- a/plots.py +++ b/plots.py @@ -215,7 +215,7 @@ pts = [] for t in Tl: try: - point = fluid(P=P, T=t+273.15) + point = fluid(P=P, T=float(t)+273.15) if fluid == iapws.IAPWS97 and not region5 and \ point.region == 5: continue @@ -242,7 +242,9 @@ if xAxis != "h" and yAxis != "h": print("Calculating isoenthalpic lines...") H_: Dict[str, Dict[str, List[Any]]] = {} - for h in isoh: + for numpy_h in isoh: + # Convert numpy.Float64 to Python float. + h = float(numpy_h) print(" h=%skJ/kg" % h) H_["%s" % h] = {} pts = [] @@ -297,7 +299,7 @@ print("Calculating isochor lines...") for v in isov: print(" v=%s" % v) - pts95 = [iapws.IAPWS95(T=t, v=v) for t in Tl] + pts95 = [iapws.IAPWS95(T=float(t), v=v) for t in Tl] x = [] y = [] for p95 in pts95: @@ -396,7 +398,9 @@ plt.annotate(txt, (x[i], y[i]), rotation=rot, **labelP_kw) if xAxis != "h" and yAxis != "h": - for h in isoh: + for numpy_h in isoh: + # Convert numpy.Float64 to Python float. + h = float(numpy_h) x = H_["%s" % h]["x"] y = H_["%s" % h]["y"] diff --git a/stubs/numpy/__init__.pyi b/stubs/numpy/__init__.pyi index df8dca1..8e723ab 100644 --- a/stubs/numpy/__init__.pyi +++ b/stubs/numpy/__init__.pyi @@ -4,9 +4,14 @@ from typing import Tuple, List, Any -class Float64(float): - ... - +# With this mypy type definition, we shouldn't be able to do anything +# with the numpy.Float64 except cast them to the Python floats. +class Float64(object): + def __float__(self) -> float: + ... + +# We can still iterate over the ndarrays however, because this +# definition lies and says ndarray is derived from Tuple. class ndarray(Tuple[Float64, ...]): ... From e0e2320c189c68cff5479cea2f0ac3aed3df9c13 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Mon, 15 Mar 2021 21:18:10 -0400 Subject: [PATCH 060/102] Improve static types for derivative() I should probably look into why they don't match as well. --- iapws/humidAir.py | 2 +- iapws/iapws08.py | 2 +- iapws/iapws95.py | 2 +- iapws/iapws97.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/iapws/humidAir.py b/iapws/humidAir.py index 966cfdb..866daf3 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -707,7 +707,7 @@ def t_func(Tpar: float) -> float: self.xa_sat = A_sat*_global_M/Ma/(1-A_sat*(1-_global_M/Ma)) self.RH = (1-self.xa)/(1-self.xa_sat) - def derivative(self, z: str, x: str, y: str): + def derivative(self, z: str, x: str, y: str) -> float: """ Wrapper derivative for custom derived properties where x, y, z can be: P, T, v, rho, u, h, s, g, a diff --git a/iapws/iapws08.py b/iapws/iapws08.py index c086b8b..be6830d 100644 --- a/iapws/iapws08.py +++ b/iapws/iapws08.py @@ -253,7 +253,7 @@ def calculo(self): self.osm = None self.haline = None - def derivative(self, z: str, x: str, y: str): + def derivative(self, z: str, x: str, y: str) -> float: """ Wrapper derivative for custom derived properties where x, y, z can be: P, T, v, u, h, s, g, a diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 857339b..639c499 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -1639,7 +1639,7 @@ def fill(self, fase: _fase, estado: Dict[str, float]) -> None: fase.epsilon = None fase.n = None - def derivative(self, z: str, x: str, y: str, fase: _fase): + def derivative(self, z: str, x: str, y: str, fase: _fase) -> float: """ Wrapper derivative for custom derived properties where x, y, z can be: P, T, v, rho, u, h, s, g, a diff --git a/iapws/iapws97.py b/iapws/iapws97.py index 426fcb2..1722761 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -4735,7 +4735,7 @@ def fill(self, fase: _fase, estado: Dict[str, float]): except NotImplementedError: fase.n = None - def derivative(self, z: str, x: str, y: str, fase): + def derivative(self, z: str, x: str, y: str, fase: _fase) -> float: """ Wrapper derivative for custom derived properties where x, y, z can be: P, T, v, u, h, s, g, a From 4c146ed0826f9cf93a3961fd70e9db3bc06fc5ef Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 02:23:08 -0400 Subject: [PATCH 061/102] Work around a mypy quirk with type ordering and function definiton. The problem seems to be that the functions don't get defined in the order that they appear in the source code, and mypy gets confused about whether T, P, rho, and A are None or not. The assertions in this awkward locatioin make mypy happy. We could pass the parameters into fsolve, or perhaps it would be easier to just set all three values to valid floats in calculable before entering this function. --- iapws/humidAir.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/iapws/humidAir.py b/iapws/humidAir.py index 866daf3..e0d84d4 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -659,11 +659,17 @@ def calculo(self) -> None: # Thermodynamic definition if self._mode == "TP": def rho_func(rhopar: float) -> float: + assert(T is not None) + assert(P is not None) + assert(A is not None) fav = self._fav(T, rhopar, A) return rhopar**2*fav["fird"]/1000-P rho = float(fsolve(rho_func, 1)[0]) elif self._mode == "Prho": def t_func(Tpar: float) -> float: + assert(P is not None) + assert(rho is not None) + assert(A is not None) fav = self._fav(Tpar, rho, A) return rho**2*fav["fird"]/1000-P T = float(fsolve(t_func, 300)[0]) From a3596dde0416ea6cd6f02db0749464d7adb60c43 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 19:58:42 -0400 Subject: [PATCH 062/102] Covert from initializing to None to nan in _fase. It appears that only epsilon and n are really optional in the final class status. Even if someone somehow got a partial result, a nan wouldn't be the end of the world, and it makes typing the fields a lot cleaner. --- iapws/_utils.py | 131 ++++++++++++++++++++++++++---------------------- 1 file changed, 71 insertions(+), 60 deletions(-) diff --git a/iapws/_utils.py b/iapws/_utils.py index 1b41a59..5717926 100644 --- a/iapws/_utils.py +++ b/iapws/_utils.py @@ -65,71 +65,82 @@ def getphase(Tc: float, Pc: float, T: float, P: float, x: float, region: int) -> class _fase(object): """Class to implement a null phase""" - v: Optional[float] = None - rho: Optional[float] = None - - h: Optional[float] = None - s: Optional[float] = None - u: Optional[float] = None - a: Optional[float] = None - g: Optional[float] = None - - cp: Optional[float] = None - cv: Optional[float] = None - cp_cv: Optional[float] = None - w: Optional[float] = None - Z: Optional[float] = None - fi: Optional[float] = None - f: Optional[float] = None - - mu: Optional[float] = None - k: Optional[float] = None - nu: Optional[float] = None - Prandt: Optional[float] = None + # One always computed form the other + v: float = float('nan') + rho: float = float('nan') + + h: float = float('nan') + s: float = float('nan') + + cv: float = float('nan') + alfap: float = float('nan') + betap: float = float('nan') + cp: float = float('nan') + kappa: float = float('nan') + alfav: float = float('nan') + + g: float = float('nan') + fi: float = float('nan') + + w: float = float('nan') + Z: float = float('nan') + + drhodP_T: float = float('nan') + mu: float = float('nan') + cp_cv: float = float('nan') + k: float = float('nan') + epsilon: Optional[float] = None - alfa: Optional[float] = None n: Optional[float] = None - alfap: Optional[float] = None - betap: Optional[float] = None - joule: Optional[float] = None - Gruneisen: Optional[float] = None - alfav: Optional[float] = None - kappa: Optional[float] = None - betas: Optional[float] = None - gamma: Optional[float] = None - Kt: Optional[float] = None - kt: Optional[float] = None - Ks: Optional[float] = None - ks: Optional[float] = None - dpdT_rho: Optional[float] = None - dpdrho_T: Optional[float] = None - drhodT_P: Optional[float] = None - drhodP_T: Optional[float] = None - dhdT_rho: Optional[float] = None - dhdT_P: Optional[float] = None - dhdrho_T: Optional[float] = None - dhdrho_P: Optional[float] = None - dhdP_T: Optional[float] = None - dhdP_rho: Optional[float] = None - - Z_rho: Optional[float] = None - IntP: Optional[float] = None - hInput: Optional[float] = None + # -------------------------------------------- + # Calculated identically between 95 and 97 + u: float = float('nan') + a: float = float('nan') + nu: float = float('nan') + Prandt: float = float('nan') + alfa: float = float('nan') + f: float = float('nan') + + # Calculated similarly, but not identically? + joule: float = float('nan') + gamma: float = float('nan') + deltat: float = float('nan') + + # Calculated on 95 only from earlier variables and self.M + rhoM: float = float('nan') + M: float = float('nan') + hM: float = float('nan') + sM: float = float('nan') + uM: float = float('nan') + aM: float = float('nan') + gM: float = float('nan') + cvM: float = float('nan') + cpM: float = float('nan') + Z_rho: float = float('nan') + + # Derivatives calculated only in IAPWS95 + dpdT_rho: float = float('nan') + dpdrho_T: float = float('nan') + drhodT_P: float = float('nan') + dhdT_rho: float = float('nan') + dhdT_P: float = float('nan') + dhdrho_T: float = float('nan') + dhdrho_P: float = float('nan') + dhdP_T: float = float('nan') + dhdP_rho: float = float('nan') + kt: float = float('nan') + ks: float = float('nan') + Ks: float = float('nan') + Kt: float = float('nan') + betas: float = float('nan') + Gruneisen: float = float('nan') + IntP: float = float('nan') + hInput: float = float('nan') # Properties added because various methods set/access them? - xkappa: Optional[float] = None - kappas: Optional[float] = None - deltat: Optional[float] = None - rhoM: Optional[float] = None - M: Optional[float] = None - hM: Optional[float] = None - sM: Optional[float] = None - uM: Optional[float] = None - aM: Optional[float] = None - gM: Optional[float] = None - cvM: Optional[float] = None - cpM: Optional[float] = None + xkappa: float = float('nan') + kappas: float = float('nan') def deriv_H(state: Any, z: str, x: str, y: str, fase: _fase) -> float: From a29b333025d576bd8634ccb283dedcdf9528dbed Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 20:02:54 -0400 Subject: [PATCH 063/102] Make IAPWS97 an _fase class. This is consistent with passing it as argument4 to derivative, and accessing cp and w members that are only defined in _fase. I'm not sure if this was the intended class hierarchy, but it's certainly looking that way to me. Resolves last typing issues in iapws08. --- iapws/iapws97.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iapws/iapws97.py b/iapws/iapws97.py index 1722761..9dfc0cd 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -4221,7 +4221,7 @@ def prop0(T: float, P: float) -> Dict[str, float]: return prop0 -class IAPWS97(object): +class IAPWS97(_fase): """Class to model a state of liquid water or steam with the IAPWS-IF97 Parameters From f40027a21127300315171356f552a2bc85c54a73 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 20:07:40 -0400 Subject: [PATCH 064/102] Remove None elements that were never accessed and confused mypy. Also type the J list more consistently as float. --- iapws/_iapws.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iapws/_iapws.py b/iapws/_iapws.py index 2fe0d70..d2c4980 100644 --- a/iapws/_iapws.py +++ b/iapws/_iapws.py @@ -989,8 +989,8 @@ def _Dielectric(rho: float, T: float) -> float: d = rho/rhoc Tr = Tc/T - I = [1, 1, 1, 2, 3, 3, 4, 5, 6, 7, 10, None] - J = [0.25, 1, 2.5, 1.5, 1.5, 2.5, 2, 2, 5, 0.5, 10, None] + I = [1, 1, 1, 2, 3, 3, 4, 5, 6, 7, 10] + J = [0.25, 1.0, 2.5, 1.5, 1.5, 2.5, 2.0, 2.0, 5.0, 0.5, 10.0] n = [0.978224486826, -0.957771379375, 0.237511794148, 0.714692244396, -0.298217036956, -0.108863472196, .949327488264e-1, -.980469816509e-2, .165167634970e-4, .937359795772e-4, -.12317921872e-9, From 58fb6f5d690c49369983e5ee66c2339c0c774dd9 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 20:14:37 -0400 Subject: [PATCH 065/102] Initialize r2 and r2p as a complex zero. --- iapws/_iapws.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iapws/_iapws.py b/iapws/_iapws.py index d2c4980..0c547f9 100644 --- a/iapws/_iapws.py +++ b/iapws/_iapws.py @@ -159,7 +159,7 @@ def _Ice(T: float, P: float) -> Dict[str, float]: gop += gok[k]*1e-3*k/Pt*(Pr-P0)**(k-1) for k in range(2, 5): gopp += gok[k]*1e-3*k*(k-1)/Pt**2*(Pr-P0)**(k-2) - r2 = r2p = 0.0 + r2 = r2p = complex(0.0, 0.0) for k in range(3): r2 += r2k[k]*(Pr-P0)**k for k in range(1, 3): From fd05e3d14fb68aeeb3014459324d2f1246a447ca Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 20:17:29 -0400 Subject: [PATCH 066/102] Type propiedades explicitly to make clear the values are optional. --- iapws/iapws97.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iapws/iapws97.py b/iapws/iapws97.py index 9dfc0cd..d8d2301 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -3602,7 +3602,7 @@ def _Region4(P: float, x: float) -> Dict[str, Optional[float]]: P1 = _Region1(T, P) P2 = _Region2(T, P) - propiedades = {} + propiedades: Dict[str, Optional[float]] = {} propiedades["T"] = T propiedades["P"] = P propiedades["v"] = P1["v"]+x*(P2["v"]-P1["v"]) From f4ac08fb0b8d62a6611946193d3ee12ae53dca8f Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 20:27:41 -0400 Subject: [PATCH 067/102] Fix the last remaining my complaints with iapws97.py. Neither of these were real problems, but it's hard for mypy to know. Neither change should present and execution problems. --- iapws/iapws97.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/iapws/iapws97.py b/iapws/iapws97.py index d8d2301..fd39bec 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -4384,6 +4384,7 @@ def calculo(self): vo = _Backward3_v_PT(P, T) def rho_funcion(rho: float) -> float: + assert(self.kwargs["T"] is not None) return _Region3(rho, self.kwargs["T"])["P"]-P rho = float(newton(rho_funcion, 1/vo)) propiedades = _Region3(rho, T) @@ -4730,10 +4731,11 @@ def fill(self, fase: _fase, estado: Dict[str, float]): except NotImplementedError: fase.epsilon = None fase.Prandt = fase.mu*fase.cp*1000/fase.k - try: - fase.n = _Refractive(fase.rho, self.T, self.kwargs["l"]) - except NotImplementedError: - fase.n = None + if self.kwargs["l"] is not None: + try: + fase.n = _Refractive(fase.rho, self.T, self.kwargs["l"]) + except NotImplementedError: + fase.n = None def derivative(self, z: str, x: str, y: str, fase: _fase) -> float: """ From b5b327097ec215e0538c1c841eadd8ec6eb8550e Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 20:34:48 -0400 Subject: [PATCH 068/102] Change _thermo to always return a float. This is a minor external API change, but it wasn't really documented that the function might return None before. It seems cleaner from a type perspective to use nan here than None. --- iapws/ammonia.py | 4 ++-- iapws/humidAir.py | 2 +- iapws/iapws95.py | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/iapws/ammonia.py b/iapws/ammonia.py index 1c6471b..550b83f 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -140,7 +140,7 @@ def _visco(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: return mu*1e-6 # fase is unused - def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> Optional[float]: + def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: """Equation for the thermal conductivity Parameters @@ -169,7 +169,7 @@ def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> Optiona if rho == rhoc and T == self.Tc: warnings.warn("Thermal conductiviy undefined in critical point") - return None + return float('nan') # Eq 6 no = [0.3589e-1, -0.1750e-3, 0.4551e-6, 0.1685e-9, -0.4828e-12] diff --git a/iapws/humidAir.py b/iapws/humidAir.py index e0d84d4..e538172 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -422,7 +422,7 @@ def _visco(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: mu = muo+mur return mu*1e-6 - def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> Optional[float]: + def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: """Equation for the thermal conductivity Parameters diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 639c499..e98a697 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -1545,7 +1545,7 @@ def _visco(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: raise NotImplementedError # Derived classes must implement _thermo to call fill() - def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> Optional[float]: + def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: raise NotImplementedError def fill(self, fase: _fase, estado: Dict[str, float]) -> None: @@ -2729,7 +2729,7 @@ def _visco(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: drho = 1e3/self.R/1.5/Tc/(1+2*delta*st["fird"]+delta**2*st["firdd"]) return _Viscosity(rho, T, fase, drho) - def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> Optional[float]: + def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: ref = IAPWS95() st = ref._Helmholtz(rho, 1.5*Tc) delta = rho/rhoc @@ -2859,7 +2859,7 @@ def _visco(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: return _D2O_Viscosity(rho, T) # fase is unused - def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> Optional[float]: + def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: return _D2O_ThCond(rho, T) def _surface(self, T: float) -> float: From 14b58acb54a9453c6b6b757197b4af17958f5b7b Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 20:40:33 -0400 Subject: [PATCH 069/102] Work around some more mypy confusion involving the kwarg being None. --- iapws/iapws95.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/iapws/iapws95.py b/iapws/iapws95.py index e98a697..d3b80ea 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -1625,19 +1625,19 @@ def fill(self, fase: _fase, estado: Dict[str, float]) -> None: fase.nu = fase.mu/fase.rho fase.alfa = fase.k/1000/fase.rho/fase.cp fase.Prandt = fase.mu*fase.cp*1000/fase.k + fase.epsilon = None + fase.n = None if self.name == "water": try: fase.epsilon = _Dielectric(fase.rho, self.T) except NotImplementedError: fase.epsilon = None - try: - fase.n = _Refractive(fase.rho, self.T, self.kwargs["l"]) - except NotImplementedError: - fase.n = None - else: - fase.epsilon = None - fase.n = None + if self.kwargs["l"] is not None: + try: + fase.n = _Refractive(fase.rho, self.T, self.kwargs["l"]) + except NotImplementedError: + fase.n = None def derivative(self, z: str, x: str, y: str, fase: _fase) -> float: """ From a18bd0769b3ba314fa4dc22881095b6d328094cc Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 20:54:45 -0400 Subject: [PATCH 070/102] Document that phases have names set by the subclasses. --- iapws/_utils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iapws/_utils.py b/iapws/_utils.py index 5717926..ae49bdd 100644 --- a/iapws/_utils.py +++ b/iapws/_utils.py @@ -65,6 +65,10 @@ def getphase(Tc: float, Pc: float, T: float, P: float, x: float, region: int) -> class _fase(object): """Class to implement a null phase""" + # The name of the substance. + # Set in NH3, Air, IAPWS95, D2O, and IAPWS97. + name: str = "unknown" + # One always computed form the other v: float = float('nan') rho: float = float('nan') From 02f026e5952fd129fb012aeac69010fa19540bd7 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 20:55:43 -0400 Subject: [PATCH 071/102] Document that some subclasses define the _surf coefficients. Also intialize sigma with a float. --- iapws/iapws95.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/iapws/iapws95.py b/iapws/iapws95.py index d3b80ea..c6b0db4 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -398,6 +398,8 @@ class MEoS(_fase): _rhoL_eq: int _rhoL_ao: List[float] _rhoL_exp: List[float] + # Defined in derived classes NH3 and Air. + _surf: Dict[str, List[float]] kwargs = {"T": 0.0, "P": 0.0, @@ -2179,7 +2181,7 @@ def _surface(self, T: float) -> float: exp: exponent """ tau = 1-T/self.Tc - sigma = 0 + sigma = 0.0 for n, t in zip(self._surf["sigma"], self._surf["exp"]): sigma += n*tau**t return sigma From 4da85c548785ca68f688f034e722d84de857996b Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 21:01:55 -0400 Subject: [PATCH 072/102] Mark Fi0 as class variable defined by subclasses. Convert constants to consistently signal that they're floats. --- iapws/ammonia.py | 4 ++-- iapws/humidAir.py | 6 +++--- iapws/iapws95.py | 11 ++++++----- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/iapws/ammonia.py b/iapws/ammonia.py index 550b83f..f1fa7c5 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -46,8 +46,8 @@ class NH3(MEoS): f_acent = 0.25601 momentoDipolar = 1.470 - Fi0 = {"ao_log": [1, -1], - "pow": [0, 1, 1./3, -1.5, -1.75], + Fi0 = {"ao_log": [1.0, -1.0], + "pow": [0.0, 1.0, 1.0/3.0, -1.5, -1.75], "ao_pow": [-15.81502, 4.255726, 11.47434, -1.296211, 0.5706757], "ao_exp": [], "titao": [], "ao_hyp": [], "hyp": []} diff --git a/iapws/humidAir.py b/iapws/humidAir.py index e538172..d2a417a 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -285,15 +285,15 @@ class Air(MEoSBlend): f_acent = 0.0335 momentoDipolar = 0.0 - Fi0 = {"ao_log": [1, 2.490888032], - "pow": [-3, -2, -1, 0, 1, 1.5], + Fi0 = {"ao_log": [1.0, 2.490888032], + "pow": [-3.0, -2.0, -1.0, 0.0, 1.0, 1.5], "ao_pow": [0.6057194e-7, -0.210274769e-4, -0.158860716e-3, 9.7450251743948, 10.0986147428912, -0.19536342e-3], "ao_exp": [0.791309509, 0.212236768], "titao": [25.36365, 16.90741], "ao_exp2": [-0.197938904], "titao2": [87.31279], - "sum2": [2./3], + "sum2": [2.0/3.0], } _constant_R = 8.31451 diff --git a/iapws/iapws95.py b/iapws/iapws95.py index c6b0db4..e35c6f6 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -400,6 +400,7 @@ class MEoS(_fase): _rhoL_exp: List[float] # Defined in derived classes NH3 and Air. _surf: Dict[str, List[float]] + Fi0: Dict[str, List[float]] kwargs = {"T": 0.0, "P": 0.0, @@ -2463,8 +2464,8 @@ class IAPWS95(MEoS): f_acent = 0.3443 momentoDipolar = 1.855 - Fi0 = {"ao_log": [1, 3.00632], - "pow": [0, 1], + Fi0 = {"ao_log": [1.0, 3.00632], + "pow": [0.0, 1.0], "ao_pow": [-8.3204464837497, 6.6832105275932], "ao_exp": [0.012436, 0.97315, 1.2795, 0.96956, 0.24873], "titao": [1.28728967, 3.53734222, 7.74073708, 9.24437796, @@ -2810,11 +2811,11 @@ class D2O(MEoS): f_acent = 0.364 momentoDipolar = 1.9 - Fi0 = {"ao_log": [1, 3], - "pow": [0, 1], + Fi0 = {"ao_log": [1.0, 3.0], + "pow": [0.0, 1.0], "ao_pow": [-8.670994022646, 6.96033578458778], "ao_exp": [0.010633, 0.99787, 2.1483, 0.3549], - "titao": [308/Tc, 1695/Tc, 3949/Tc, 10317/Tc], + "titao": [308.0/Tc, 1695.0/Tc, 3949.0/Tc, 10317.0/Tc], "ao_hyp": [], "hyp": []} _constant_R = 8.3144598 From 49c71f3923c18c7295cdeeae0aaab218cb2a80c2 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 21:06:01 -0400 Subject: [PATCH 073/102] Add mypy.ini and .flake8 files. Probably should have commited these first rather than last, but I was waiting to see if I needed to change the configuration at all. With this commit, mypy runs to completion and returns no errors. --- .flake8 | 47 +++++++++++++++++++++++++++++++++++++++++++++++ mypy.ini | 30 ++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 .flake8 create mode 100644 mypy.ini diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..33bead1 --- /dev/null +++ b/.flake8 @@ -0,0 +1,47 @@ +[flake8] +max-line-length = 90 +accept-encodings = utf-8 +mypy_config = mypy.ini + +ignore = + # 1669 instances + A501, # A501 prefer built-in rounding of assertAlmostEqual() for 'round' expressions + + E226, # E226 missing whitespace around arithmetic operator (5939 instances) + + E265, # E265 block comment should start with '# ' (47 instances) + + E501, # E501 line too long (X > L characters) (127 instances) + + E741, # E741 ambiguous variable name 'l', 'I' (45 instances, mostly 'I/l') + + # Since this commit Python recommends breaking before operators. + # https://github.com/python/peps/commit/c59c4376ad233a62ca4b3a6060c81368bd21e85b + W503, # W503 line break before binary operator + + # Disable warnings about missing docstrings. + D107, # D107 Missing docstring in __init__ (11 instances) + + # (26 instances), Many summary lines are fairly complicated. + D205, # D205 1 blank line required between summary line and description + + D400, # D400 First line should end with a period (230 instances) + + D401, # D401 First line should be in imperative mood (20 instances) + + # One spurious instance, see: https://github.com/PyCQA/pydocstyle/issues/412 + D412, # D412 No blank lines allowed between a section header and its content + + R504, # R504 value assigned to variable is only used as a return value (42 instances) + + N081, # N801 class name 'fase' should use CapWords convention (12 instances) + + N802, # N802 function name '...' should be lowercase (143 instances) + + N803, # N803 argument name 'X' should be lowercase (138 instances) + + N806, # N806 variable 'X' in function should be lowercase (1014 instances) + + N815, # N815 variable 'xX' in class scope should not be mixedCase (24 instances) + + N816 # N816 variable 'isoP_kw' in global scope should not be mixedCase (11 instances) diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 0000000..1c4198e --- /dev/null +++ b/mypy.ini @@ -0,0 +1,30 @@ +[mypy] +mypy_path = stubs +files = **/*.py +python_version = 3.8 +#show_error_codes = True +#pretty = True +warn_unused_configs = True +warn_redundant_casts = True +strict_optional = True + +# Strict mode; enables the following flags: --warn-unused-configs, +# --disallow-any-generics, --disallow-subclassing-any, +# --disallow-untyped-calls, --disallow-untyped-defs, +# --disallow-incomplete-defs, --check-untyped-defs, +# --disallow-untyped-decorators, --no-implicit-optional, +# --warn-redundant-casts, --warn-unused-ignores, --warn-return-any, +# --no-implicit-reexport + +[iapws.*] +disallow_any_generics = True +disallow_subclassing_any = True +disallow_untyped_calls = True +disallow_untyped_defs = True +disallow_incomplete_defs = True +check_untyped_defs = True +disallow_untyped_decorators = True +no_implicit_optional = True +warn_unused_ignores = True +warn_return_any = True +no_implicit_reexport = True From 3ce2c8d5ce0b0d66976d291a8fef7e9a01176736 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 21:10:26 -0400 Subject: [PATCH 074/102] Enable 91 new mypy errors by typing test cases. --- test.py | 90 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/test.py b/test.py index 19add97..6260708 100755 --- a/test.py +++ b/test.py @@ -43,7 +43,7 @@ class Test(unittest.TestCase): Run for python2 and python3 before to release distribution """ - def test_Helmholtz(self): + def test_Helmholtz(self) -> None: """Table 6 from IAPWS95, pag 14""" T = 500 rho = 838.025 @@ -73,7 +73,7 @@ def test_Helmholtz(self): self.assertEqual(round(vir["B"]/fluid.rhoc, 11), -0.555366808e-2) self.assertEqual(round(vir["C"]/fluid.rhoc**2, 14), -0.669015050e-5) - def test_phase(self): + def test_phase(self) -> None: """Table 7 from IAPWS95, pag 14""" state = IAPWS95(rho=996.556, T=300) # See footnote for imprecise P value in last significant figures @@ -142,7 +142,7 @@ def test_phase(self): self.assertEqual(round(state.w, 5), 2019.33608) self.assertEqual(round(state.s, 8), 4.17223802) - def test_saturation(self): + def test_saturation(self) -> None: """Table 8 from IAPWS95, pag 14""" fluid = IAPWS95() @@ -179,7 +179,7 @@ def test_saturation(self): self.assertEqual(round(liquid["s"], 8), 3.80194683) self.assertEqual(round(vapor["s"], 8), 5.18506121) - def test_LowT(self): + def test_LowT(self) -> None: """Table 3, pag 5""" fluid = IAPWS95() fex, fext, fextt = fluid._phiex(50) @@ -196,7 +196,7 @@ def test_LowT(self): fluid = IAPWS95(T=120, P=0.1) - def test_Melting(self): + def test_Melting(self) -> None: """Table 3, pag 7""" self.assertRaises(NotImplementedError, _Sublimation_Pressure, 49) self.assertRaises(NotImplementedError, _Sublimation_Pressure, 274) @@ -208,7 +208,7 @@ def test_Melting(self): self.assertEqual(round(_Melting_Pressure(320, "VI"), 2), 1356.76) self.assertEqual(round(_Melting_Pressure(550, "VII"), 2), 6308.71) - def test_Viscosity_1(self): + def test_Viscosity_1(self) -> None: """Table 4, pag 8""" self.assertEqual(round(_Viscosity(998, 298.15)*1e6, 6), 889.735100) self.assertEqual(round(_Viscosity(1200, 298.15)*1e6, 6), 1437.649467) @@ -236,7 +236,7 @@ def test_Viscosity_1(self): fluid = IAPWS95(rho=422, T=647.35) self.assertEqual(round(fluid.mu*1e6, 6), 49.436256) - def test_ThCond(self): + def test_ThCond(self) -> None: """Table 4, pag 10""" self.assertEqual(round(_ThCond(0, 298.15)*1000, 7), 18.4341883) self.assertEqual(round(_ThCond(998, 298.15)*1000, 6), 607.712868) @@ -277,7 +277,7 @@ def test_ThCond(self): fluid = IAPWS97(T=647.35, P=P) self.assertEqual(round(fluid.k*1000, 5), 1241.82415) - def test_Tension(self): + def test_Tension(self) -> None: """Selected values from table 1""" self.assertRaises(NotImplementedError, _Tension, 230) self.assertEqual(round(_Tension(273.16)*1000, 2), 75.65) @@ -301,7 +301,7 @@ def test_Tension(self): self.assertEqual(round(_Tension(623.15)*1000, 2), 3.67) self.assertEqual(round(_Tension(643.15)*1000, 2), 0.39) - def test_Dielect(self): + def test_Dielect(self) -> None: """Table 4, pag 8""" fluid = IAPWS95(P=0.101325, T=240) self.assertEqual(round(fluid.epsilon, 5), 104.34982) @@ -324,7 +324,7 @@ def test_Dielect(self): fluid = IAPWS95(P=500, T=870) self.assertEqual(round(fluid.epsilon, 5), 15.09746) - def test_Refractive(self): + def test_Refractive(self) -> None: """Selected values from table 3, pag 6""" fluid = IAPWS95(P=0.1, T=273.15, l=0.2265) self.assertEqual(round(fluid.n, 6), 1.394527) @@ -343,7 +343,7 @@ def test_Refractive(self): fluid = IAPWS95(P=100., T=473.15, l=1.01398) self.assertEqual(round(fluid.n, 6), 1.298369) - def test_kw(self): + def test_kw(self) -> None: """Table 3, pag 5""" self.assertRaises(NotImplementedError, _Kw, *(1000, 270)) self.assertEqual(round(_Kw(1000, 300), 6), 13.906565) @@ -352,7 +352,7 @@ def test_kw(self): self.assertEqual(round(_Kw(200, 800), 6), 15.089765) self.assertEqual(round(_Kw(1200, 800), 6), 6.438330) - def test_liquid(self): + def test_liquid(self) -> None: """Table 8, pag 11""" liq = _Liquid(260) self.assertEqual(round(liq["g"], 7), -1.2659892) @@ -400,7 +400,7 @@ def test_liquid(self): self.assertWarns(Warning, _Liquid, *(375, 0.2)) self.assertRaises(NotImplementedError, _Liquid, *(375, 0.4)) - def test_superCooled(self): + def test_superCooled(self) -> None: """Table 5, pag 9""" liq = _Supercooled(273.15, 0.101325) self.assertEqual(round(liq["x"], 8), 0.09665472) @@ -450,7 +450,7 @@ def test_superCooled(self): self.assertRaises(NotImplementedError, _Supercooled, *(200, 100)) self.assertRaises(NotImplementedError, _Supercooled, *(180, 300)) - def test_auxiliarySaturation(self): + def test_auxiliarySaturation(self) -> None: """Table 1 pag 7""" fluid = IAPWS95() self.assertEqual(round(fluid._Vapor_Pressure(273.16), 9), 0.000611657) @@ -486,7 +486,7 @@ def test_auxiliarySaturation(self): self.assertEqual(round(fluid._Liquid_Entropy(647.096), 3), 4.410) self.assertEqual(round(fluid._Vapor_Entropy(647.096), 3), 4.410) - def test_IAPWS97_1(self): + def test_IAPWS97_1(self) -> None: """Table 5, pag 9""" fluid = _Region1(300, 3) self.assertEqual(round(fluid["v"], 11), 0.00100215168) @@ -527,7 +527,7 @@ def test_IAPWS97_1(self): self.assertEqual(round(_Backward1_P_hs(90, 0), 8), 91.92954727) self.assertEqual(round(_Backward1_P_hs(1500, 3.4), 8), 58.68294423) - def test_IAPWS97_2(self): + def test_IAPWS97_2(self) -> None: """Table 15, pag 17""" # Auxiliary equation for the boundary 2-3 self.assertEqual(round(_P23_T(623.15), 7), 16.5291643) @@ -595,7 +595,7 @@ def test_IAPWS97_2(self): self.assertEqual(round(_Backward2_P_hs(2800, 5.8), 9), 8.414574124) self.assertEqual(round(_Backward2_P_hs(3400, 5.8), 8), 83.76903879) - def test_IAPWS97_3(self): + def test_IAPWS97_3(self) -> None: """Table 33, pag 49""" fluid = _Region3(500, 650) self.assertEqual(round(fluid["P"], 7), 25.5837018) @@ -624,7 +624,7 @@ def test_IAPWS97_3(self): # _h_3ab pag 7 self.assertEqual(round(_h_3ab(25), 6), 2095.936454) - def test_IAPWS97_3_Sup03(self): + def test_IAPWS97_3_Sup03(self) -> None: """Test for supplementary 03 for region 3""" # _Backward3_T_Ph Table 5 pag 8 self.assertEqual(round(_Backward3_T_Ph(20, 1700), 7), 629.3083892) @@ -670,7 +670,7 @@ def test_IAPWS97_3_Sup03(self): self.assertEqual(round(_PSat_s(4.2), 8), 21.64451789) self.assertEqual(round(_PSat_s(5.2), 8), 16.68968482) - def test_IAPWS97_3_Sup04(self): + def test_IAPWS97_3_Sup04(self) -> None: """Test for supplementary 04 for region 3""" # _Backward3_P_hs Table 5 pag 10 self.assertEqual(round(_Backward3_P_hs(1700, 3.8), 8), 25.55703246) @@ -717,7 +717,7 @@ def test_IAPWS97_3_Sup04(self): self.assertEqual(round(_Backward4_T_hs(2400, 6.0), 7), 425.1373305) self.assertEqual(round(_Backward4_T_hs(2500, 5.5), 7), 522.5579013) - def test_IAPWS97_3_Sup05(self): + def test_IAPWS97_3_Sup05(self) -> None: """Test for supplementary 05 for region 3 v=f(T,P)""" # T=f(P) limit Table 3 pag 11 self.assertEqual(round(_tab_P(40), 7), 693.0341408) @@ -791,7 +791,7 @@ def test_IAPWS97_3_Sup05(self): self.assertEqual(round(_Backward3_v_PT(22, 646.89), 12), 3.798732962e-3) self.assertEqual(round(_Backward3_v_PT(22.064, 647.15), 11), 3.701940010e-3) - def test_IAPWS97_4(self): + def test_IAPWS97_4(self) -> None: """Saturation line""" # _PSat_T Table 35 pag 34 self.assertRaises(NotImplementedError, _PSat_T, 270) @@ -805,7 +805,7 @@ def test_IAPWS97_4(self): self.assertEqual(round(_TSat_P(1), 6), 453.035632) self.assertEqual(round(_TSat_P(10), 6), 584.149488) - def test_IAPWS97_5(self): + def test_IAPWS97_5(self) -> None: """Table 42, pag 40""" fluid = _Region5(1500, 0.5) self.assertEqual(round(fluid["v"], 8), 1.38455090) @@ -831,7 +831,7 @@ def test_IAPWS97_5(self): self.assertEqual(round(fluid["cp"], 8), 2.88569882) self.assertEqual(round(fluid["w"], 5), 1067.36948) - def test_IAPWS97_custom(self): + def test_IAPWS97_custom(self) -> None: """Cycle input parameter from selected point for IAPWS97""" # Region 1 P = 50 # MPa @@ -1117,7 +1117,7 @@ def test_IAPWS97_custom(self): self.assertRaises(NotImplementedError, IAPWS97, **{"P": 65, "s": 9}) self.assertRaises(NotImplementedError, IAPWS97, **{"h": 700, "s": -1}) - def test_IAPWS95_custom(self): + def test_IAPWS95_custom(self) -> None: """Cycle input parameter from selected point for IAPWS95""" P = 50 # MPa T = 470 # K @@ -1223,7 +1223,7 @@ def test_IAPWS95_custom(self): self.assertRaises(NotImplementedError, IAPWS95, **{"T": 700, "x": 0}) self.assertRaises(NotImplementedError, IAPWS95, **{"P": 25, "x": 1}) - def test_D2O(self): + def test_D2O(self) -> None: """Tables 6-8, page 12-13.""" # Table 6, pag 12""" fluid = D2O() @@ -1359,7 +1359,7 @@ def test_D2O(self): P = _D2O_Melting_Pressure(300, "VI") self.assertEqual(round(P, 6), 959.203594) - def test_D2O_Viscosity(self): + def test_D2O_Viscosity(self) -> None: """Table A5 pag 10""" mur = 55.2651e-6 Tr = 643.847 @@ -1392,7 +1392,7 @@ def test_D2O_Viscosity(self): self.assertEqual(round(_D2O_Viscosity(1.2*rhor, 1.2*Tr)/mur, 10), 0.9937870139) self.assertEqual(round(_D2O_Viscosity(1.61*rhor, 1.2*Tr)/mur, 10), 1.2711900131) - def test_D2O_ThCond(self): + def test_D2O_ThCond(self) -> None: """Table B4 pag 17""" lr = 0.742128e-3 Tr = 643.847 @@ -1429,7 +1429,7 @@ def test_D2O_ThCond(self): self.assertEqual(round(_D2O_ThCond(0.95*rhor, 1.27*Tr)/lr, 9), 299.251471210) self.assertEqual(round(_D2O_ThCond(1.37*rhor, 1.27*Tr)/lr, 9), 409.359675394) - def test_D2O_Tension(self): + def test_D2O_Tension(self) -> None: """Selected values from table 1""" self.assertRaises(NotImplementedError, _D2O_Tension, 250) self.assertEqual(round(_D2O_Tension(273.15+3.8)*1000, 2), 74.93) @@ -1453,7 +1453,7 @@ def test_D2O_Tension(self): self.assertEqual(round(_D2O_Tension(623.15)*1000, 2), 3.17) self.assertEqual(round(_D2O_Tension(643.15)*1000, 2), 0.05) - def test_Ice(self): + def test_Ice(self) -> None: """Table 6, pag 12""" ice = _Ice(273.16, 0.000611657) self.assertEqual(round(ice["g"], 12), 0.000611784135) @@ -1516,7 +1516,7 @@ def test_Ice(self): self.assertWarns(Warning, _Ice, *(273, 3)) self.assertWarns(Warning, _Ice, *(272, 1e-4)) - def test_SeaWater(self): + def test_SeaWater(self) -> None: """Table 8, pag 17-19""" # Part a, pag 17 fluid = SeaWater(T=273.15, P=0.101325, S=0.03516504) @@ -1640,7 +1640,7 @@ def test_SeaWater(self): wat = IAPWS95(T=353, P=0.101325) self.assertEqual(round(fluid.derivative("T", "P", "h")*1000-wat.joule, 7), 0) - def test_SeaWater_supp(self): + def test_SeaWater_supp(self) -> None: """Table 6, pag 9""" fluid = SeaWater(T=273.15, P=0.101325, S=0, fast=True) state = fluid._waterSupp(273.15, 0.101325) @@ -1690,7 +1690,7 @@ def test_SeaWater_supp(self): self.assertEqual(round(fluid.cp, 8), 4.17942416) self.assertEqual(round(fluid.w, 5), 1528.91242) - def test_SeaWaterIF97(self): + def test_SeaWaterIF97(self) -> None: """Table A1, pag 19-21""" fluid = SeaWater(T=273.15, P=0.101325, S=0.03516504, IF97=True) state = fluid._waterIF97(273.15, 0.101325) @@ -1921,7 +1921,7 @@ def test_SeaWaterIF97(self): # Osmotic pressure, i have no test to do self.assertEqual(round(_OsmoticPressure(300, 0.1, 0), 5), 0.0) - def test_SeaWater_thcond(self): + def test_SeaWater_thcond(self) -> None: """Table 2, pag 5""" fluid = SeaWater(T=293.15, P=0.1, S=0.035) self.assertEqual(round(_ThCond_SeaWater(T=293.15, P=0.1, S=0.035), 9), -0.004186040) @@ -1962,7 +1962,7 @@ def test_SeaWater_thcond(self): fluid = SeaWater(T=270, P=1, S=0.12) self.assertRaises(NotImplementedError, _ThCond_SeaWater, *(270, 1, 0)) - def test_SeaWater_tension(self): + def test_SeaWater_tension(self) -> None: """Table 2, pag 4""" self.assertEqual(round(_Tension_SeaWater(253.15, 0.035)*1e3, 9), 79.225179610) self.assertEqual(round(_Tension_SeaWater(298.15, 0.035)*1e3, 9), 73.068674787) @@ -1972,7 +1972,7 @@ def test_SeaWater_tension(self): self.assertEqual(round(_Tension_SeaWater(293.15, 0.120)*1e3, 9), 76.432940211) self.assertEqual(round(_Tension_SeaWater(353.15, 0.120)*1e3, 9), 66.917261258) - def test_na2so4(self): + def test_na2so4(self) -> None: """Selected point from Table 1, pag 5""" self.assertEqual(round(_solNa2SO4(523.15, 0, 0), 2), 3.54) self.assertEqual(round(_solNa2SO4(523.15, 0.25, 0.083), 2), 3.31) @@ -1990,7 +1990,7 @@ def test_na2so4(self): self.assertEqual(round(_solNa2SO4(623.15, 0.75, 2.25), 2), 2.13) self.assertRaises(NotImplementedError, _solNa2SO4, *(500, 0, 0)) - def test_critNaCl(self): + def test_critNaCl(self) -> None: """Table II, page 6""" crit = _critNaCl(0) self.assertEqual(round(crit["Tc"], 6), 647.096000) @@ -2091,7 +2091,7 @@ def test_critNaCl(self): self.assertRaises(NotImplementedError, _critNaCl, 0.2) - def test_Henry(self): + def test_Henry(self) -> None: """Table 6, Henry constants.""" # Table 6 for Henry constants self.assertRaises(NotImplementedError, _Henry, *(300, "He", "He")) @@ -2269,7 +2269,7 @@ def test_Henry(self): self.assertEqual(round(log(_Kvalue(500, "CH4", "D2O")), 4), 6.9021) self.assertEqual(round(log(_Kvalue(600, "CH4", "D2O")), 4), 3.8126) - def xest_Conductivity(self): + def xest_Conductivity(self) -> None: """Selected values from table II""" self.assertEqual(round(_Conductivity(600, 673.15), 9), 1.57e-6) self.assertEqual(round(_Conductivity(800, 1073.15), 9), 103e-6) @@ -2277,7 +2277,7 @@ def xest_Conductivity(self): self.assertEqual(round(_Conductivity(1100, 273.16), 9), 0.0333e-6) self.assertEqual(round(_Conductivity(1100, 473.15), 9), 22.8e-6) - def test_virial(self): + def test_virial(self) -> None: """Tables 7 & 8, page 10""" # Table 7, page 10 st = _virial(200) @@ -2319,7 +2319,7 @@ def test_virial(self): self.assertWarns(Warning, _virial, 50) self.assertRaises(NotImplementedError, _fugacity, *(190, 1, 0.1)) - def test_Air(self): + def test_Air(self) -> None: """Tables A1 & A2, page 363 & 366.""" # Table A1, Pag 363 self.assertEqual(round(Air._bubbleP(59.75), 6), 0.005265) @@ -2380,7 +2380,7 @@ def test_Air(self): self.assertEqual(round(f_prho.P-P, 6), 0) self.assertEqual(round(f_prho.T-T, 6), 0) - def test_AirTransport(self): + def test_AirTransport(self) -> None: """Table V, pag 28""" st = Air() self.assertEqual(round(st._visco(0, 100), 11), 7.09559e-6) @@ -2397,7 +2397,7 @@ def test_AirTransport(self): self.assertEqual(round(Air(rho=5*28.9586, T=300).k, 7), 32.6062e-3) # self.assertEqual(round(Air(rho=10.4*28.9586, T=132.64).k, 7), 75.6231e-3) - def test_HumidAir(self): + def test_HumidAir(self) -> None: """Tables 13-15 from page 19""" # Table 13 A = 0.892247719 @@ -2644,7 +2644,7 @@ def test_HumidAir(self): self.assertEqual(round(hum.cp, 8), 1.09387397) self.assertEqual(round(hum.cp-200*hum.derivative("s", "T", "P"), 8), 0) - def test_Ammonia(self): + def test_Ammonia(self) -> None: """Selected point front table of pag 42""" st = NH3(T=-77.65+273.15, x=0.5) self.assertEqual(round(st.P, 5), 0.00609) @@ -2693,7 +2693,7 @@ def test_Ammonia(self): if major == 3: self.assertWarns(Warning, st._thermo, *(235, st.Tc, st)) - def test_AmmoniaVisco(self): + def test_AmmoniaVisco(self) -> None: """Appendix II & III, page 1664 & 1667.""" # Appendix II, pag 1664 st = NH3(T=680, P=0.1) @@ -2725,7 +2725,7 @@ def test_AmmoniaVisco(self): self.assertEqual(round(st.Liquid.rhoM, 4), 19.1642) self.assertEqual(round(st.Liquid.mu*1e6, 2), 39.20) - def test_nh3h2o(self): + def test_nh3h2o(self) -> None: """Test outstanding problems in H2ONH3.""" # Range of validity Tt1 = Ttr(0) From f92f049e865cb72373089841d98163fc5c289ec4 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 21:15:24 -0400 Subject: [PATCH 075/102] Initialize floats specific to SeaWater class. --- iapws/iapws08.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/iapws/iapws08.py b/iapws/iapws08.py index be6830d..19bcef8 100644 --- a/iapws/iapws08.py +++ b/iapws/iapws08.py @@ -173,6 +173,14 @@ class SeaWater(_fase): def __init__(self, **kwargs): """Constructor, initinialice kwargs""" + self.gs = float('nan') + self.gt = float('nan') + self.gp = float('nan') + self.gsp = float('nan') + self.gtt = float('nan') + self.gtp = float('nan') + self.gpp = float('nan') + self.kwargs = SeaWater.kwargs.copy() self.__call__(**kwargs) From ecb0ca7e10b9254bef4b369050fcff9652d25389 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 22:47:10 -0400 Subject: [PATCH 076/102] Technically these can be None as the API is currently defined. I suppose in a test it's fine to say AssertEqual(), but mypy rightly notes the type inconsitency as well. --- test.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test.py b/test.py index 6260708..a7bb127 100755 --- a/test.py +++ b/test.py @@ -304,43 +304,61 @@ def test_Tension(self) -> None: def test_Dielect(self) -> None: """Table 4, pag 8""" fluid = IAPWS95(P=0.101325, T=240) + assert(fluid.epsilon is not None) self.assertEqual(round(fluid.epsilon, 5), 104.34982) fluid = IAPWS95(P=0.101325, T=300) + assert(fluid.epsilon is not None) self.assertEqual(round(fluid.epsilon, 5), 77.74735) fluid = IAPWS95(P=10, T=300) + assert(fluid.epsilon is not None) self.assertEqual(round(fluid.epsilon, 5), 78.11269) fluid = IAPWS95(P=1000, T=300) + assert(fluid.epsilon is not None) self.assertEqual(round(fluid.epsilon, 5), 103.69632) fluid = IAPWS95(P=10, T=650) + assert(fluid.epsilon is not None) self.assertEqual(round(fluid.epsilon, 5), 1.26715) fluid = IAPWS95(P=100, T=650) + assert(fluid.epsilon is not None) self.assertEqual(round(fluid.epsilon, 5), 17.71733) fluid = IAPWS95(P=500, T=650) + assert(fluid.epsilon is not None) self.assertEqual(round(fluid.epsilon, 5), 26.62132) fluid = IAPWS95(P=10, T=870) + assert(fluid.epsilon is not None) self.assertEqual(round(fluid.epsilon, 5), 1.12721) fluid = IAPWS95(P=100, T=870) + assert(fluid.epsilon is not None) self.assertEqual(round(fluid.epsilon, 5), 4.98281) fluid = IAPWS95(P=500, T=870) + assert(fluid.epsilon is not None) self.assertEqual(round(fluid.epsilon, 5), 15.09746) def test_Refractive(self) -> None: """Selected values from table 3, pag 6""" fluid = IAPWS95(P=0.1, T=273.15, l=0.2265) + assert(fluid.n is not None) self.assertEqual(round(fluid.n, 6), 1.394527) fluid = IAPWS95(P=10., T=273.15, l=0.2265) + assert(fluid.n is not None) self.assertEqual(round(fluid.n, 6), 1.396526) fluid = IAPWS95(P=1., T=373.15, l=0.2265) + assert(fluid.n is not None) self.assertEqual(round(fluid.n, 6), 1.375622) fluid = IAPWS95(P=100., T=373.15, l=0.2265) + assert(fluid.n is not None) self.assertEqual(round(fluid.n, 6), 1.391983) fluid = IAPWS95(P=0.1, T=473.15, l=0.589) + assert(fluid.n is not None) self.assertEqual(round(fluid.n, 7), 1.0001456) fluid = IAPWS95(P=1., T=773.15, l=0.589) + assert(fluid.n is not None) self.assertEqual(round(fluid.n, 7), 1.0008773) fluid = IAPWS95(P=10., T=273.15, l=1.01398) + assert(fluid.n is not None) self.assertEqual(round(fluid.n, 6), 1.327710) fluid = IAPWS95(P=100., T=473.15, l=1.01398) + assert(fluid.n is not None) self.assertEqual(round(fluid.n, 6), 1.298369) def test_kw(self) -> None: From feba249843d68dd031b6582174d7d9f5ae366de3 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 22:54:54 -0400 Subject: [PATCH 077/102] Reuse variables only if they have the same type. --- test.py | 70 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/test.py b/test.py index a7bb127..0f5cc11 100755 --- a/test.py +++ b/test.py @@ -852,7 +852,7 @@ def test_IAPWS97_5(self) -> None: def test_IAPWS97_custom(self) -> None: """Cycle input parameter from selected point for IAPWS97""" # Region 1 - P = 50 # MPa + P = 50.0 # MPa T = 470 # K f_pt = IAPWS97(P=P, T=T) f_ph = IAPWS97(h=f_pt.h, P=f_pt.P) @@ -861,7 +861,7 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_hs.P-P, 6), 0) self.assertEqual(round(f_hs.T-T, 6), 0) - P = 20 # MPa + P = 20.0 # MPa T = 370 # K f_pt = IAPWS97(P=P, T=T) f_ph = IAPWS97(h=f_pt.h, P=f_pt.P) @@ -871,7 +871,7 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_hs.T-T, 6), 0) # Region 2 - P = 25 # MPa + P = 25.0 # MPa T = 700 # K f_pt = IAPWS97(P=P, T=T) f_ph = IAPWS97(h=f_pt.h, P=f_pt.P) @@ -880,7 +880,7 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_hs.P-P, 6), 0) self.assertEqual(round(f_hs.T-T, 6), 0) - P = 10 # MPa + P = 10.0 # MPa T = 700 # K f_pt = IAPWS97(P=P, T=T) f_ph = IAPWS97(h=f_pt.h, P=f_pt.P) @@ -898,7 +898,7 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_hs.P-P, 6), 0) self.assertEqual(round(f_hs.T-T, 6), 0) - P = 0.01 # MPa + P = 0.01 # MPa T = 1000 # K f_pt = IAPWS97(P=P, T=T) f_ph = IAPWS97(h=f_pt.h, P=f_pt.P) @@ -907,7 +907,7 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_hs.P-P, 6), 0) self.assertEqual(round(f_hs.T-T, 6), 0) - P = 2 # MPa + P = 2.0 # MPa T = 1000 # K f_pt = IAPWS97(P=P, T=T) f_ph = IAPWS97(h=f_pt.h, P=f_pt.P) @@ -917,7 +917,7 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_hs.T-T, 6), 0) # Region 3 - P = 50 # MPa + P = 50.0 # MPa T = 700 # K f_pt = IAPWS97(P=P, T=T) f_ph = IAPWS97(h=f_pt.h, P=f_pt.P) @@ -926,7 +926,7 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_hs.P-P, 6), 0) self.assertEqual(round(f_hs.T-T, 6), 0) - P = 20 # MPa + P = 20.0 # MPa s = 4 # kJ/kgK f_ps = IAPWS97(P=P, s=s) f_ph = IAPWS97(h=f_pt.h, P=f_pt.P) @@ -935,18 +935,18 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_hs.P-P, 6), 0) self.assertEqual(round(f_hs.s-s, 6), 0) - P = 19 # MPa + P = 19.0 # MPa f_px = IAPWS97(P=P, x=0) f_tx = IAPWS97(T=f_px.T, x=f_px.x) self.assertEqual(round(f_tx.P-P, 3), 0) self.assertEqual(round(f_tx.x, 6), 0) - P = 19 # MPa + P = 19.0 # MPa f_px = IAPWS97(P=P, x=1) f_tx = IAPWS97(T=f_px.T, x=f_px.x) self.assertEqual(round(f_tx.P-P, 3), 0) self.assertEqual(round(f_tx.x, 6), 1) - P = 21 # MPa + P = 21.0 # MPa f_px = IAPWS97(P=P, x=1) f_tx = IAPWS97(T=f_px.T, x=f_px.x) self.assertEqual(round(f_tx.P-P, 2), 0) @@ -974,7 +974,7 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_tx.P-P, 2), 0) self.assertEqual(round(f_tx.x, 3), 1) - P = 24. # MPa + P = 24.0 # MPa T = 630 # K f_pt = IAPWS97(P=P, T=T) f_hs = IAPWS97(h=f_pt.h, s=f_pt.s) @@ -1041,7 +1041,7 @@ def test_IAPWS97_custom(self) -> None: f_hs = IAPWS97(h=f_px.h, s=f_px.s) self.assertEqual(round(f_hs.T-T, 0), 0) - P = 17 # MPa + P = 17.0 # MPa h = 2000 # kJkg f_ph = IAPWS97(P=P, h=h) f_ps = IAPWS97(P=f_ph.P, s=f_ph.s) @@ -1061,7 +1061,7 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_hs.T-T, 6), 0) # Region 5 - P = 25 # MPa + P = 25.0 # MPa T = 1100 # K f_pt = IAPWS97(P=P, T=T) f_ph = IAPWS97(h=f_pt.h, P=f_pt.P) @@ -1070,7 +1070,7 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_hs.P-P, 6), 0) self.assertEqual(round(f_hs.T-T, 6), 0) - P = 10 # MPa + P = 10.0 # MPa T = 1100 # K f_pt = IAPWS97(P=P, T=T) f_ph = IAPWS97(h=f_pt.h, P=f_pt.P) @@ -1079,7 +1079,7 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_hs.P-P, 6), 0) self.assertEqual(round(f_hs.T-T, 6), 0) - P = 20 # MPa + P = 20.0 # MPa T = 1100 # K f_pt = IAPWS97(P=P, T=T) f_ph = IAPWS97(h=f_pt.h, P=f_pt.P) @@ -1089,12 +1089,14 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_hs.T-T, 6), 0) # P-T subregion 3 - P = [17, 21, 21, 21, 21, 22, 23.2, 23.2, 23.2, 23.2, 23.2, 23.2, 23.2, - 23, 23, 22.2, 22.065, 22.065, 22.065, 22.065, 21.8, 22] - T = [625, 625, 640, 643, 645, 630, 640, 650, 651, 652, 653, 656, 660, - 640, 652, 647, 646, 647.05, 647.1, 647.2, 647, 647] - for p, t in zip(P, T): - f_pt = IAPWS97(P=p, T=t) + Plist = [17.0, 21.0, 21.0, 21.0, 21.0, 22.0, 23.2, 23.2, 23.2, 23.2, + 23.2, 23.2, 23.2, 23.0, 23.0, 22.2, 22.065, 22.065, 22.065, + 22.065, 21.8, 22.0] + Tlist = [625.0, 625.0, 640.0, 643.0, 645.0, 630.0, 640.0, 650.0, 651.0, + 652.0, 653.0, 656.0, 660.0, 640.0, 652.0, 647.0, 646.0, 647.05, + 647.1, 647.2, 647.0, 647.0] + for p, t in zip(Plist, Tlist): + f_pt = IAPWS97(P=float(p), T=t) f_ph = IAPWS97(h=f_pt.h, P=f_pt.P) f_ps = IAPWS97(P=f_ph.P, s=f_ph.s) f_hs = IAPWS97(h=f_ps.h, s=f_ps.s) @@ -1102,9 +1104,9 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_hs.T-t, 6), 0) # Other h-s region - h = [2700, 2700, 1500, 2500, 2000, 2000, 3000, 2400, 2500, 2850, 2600] - s = [5.15, 5.87, 3.5, 5, 5.5, 7, 6, 5.1, 5.05, 5.25, 5.25] - for H, S in zip(h, s): + hlist = [2700, 2700, 1500, 2500, 2000, 2000, 3000, 2400, 2500, 2850, 2600] + slist = [5.15, 5.87, 3.5, 5, 5.5, 7, 6, 5.1, 5.05, 5.25, 5.25] + for H, S in zip(hlist, slist): f_hs = IAPWS97(h=H, s=S) f_pt = IAPWS97(P=f_hs.P, T=f_hs.T) self.assertEqual(round(f_hs.h-H, 6), 0) @@ -1137,7 +1139,7 @@ def test_IAPWS97_custom(self) -> None: def test_IAPWS95_custom(self) -> None: """Cycle input parameter from selected point for IAPWS95""" - P = 50 # MPa + P = 50.0 # MPa T = 470 # K f_pt = IAPWS95_PT(P, T) f_ph = IAPWS95_Ph(f_pt.P, f_pt.h) @@ -1146,7 +1148,7 @@ def test_IAPWS95_custom(self) -> None: self.assertEqual(round(f_hs.P-P, 5), 0) self.assertEqual(round(f_hs.T-T, 5), 0) - P = 2 # MPa + P = 2.0 # MPa f_px = IAPWS95_Px(P, 0.5) f_tx = IAPWS95_Tx(f_px.T, f_px.x) f_tv = IAPWS95(T=f_px.T, v=f_px.v) @@ -1166,7 +1168,7 @@ def test_IAPWS95_custom(self) -> None: self.assertEqual(round(f_Prho.P-P, 5), 0) self.assertEqual(round(f_Prho.x-0.5, 5), 0) - P = 50 # MPa + P = 50.0 # MPa T = 770 # K f_pt = IAPWS95_PT(P, T) f_tv = IAPWS95(T=f_pt.T, v=f_pt.v) @@ -1224,7 +1226,7 @@ def test_IAPWS95_custom(self) -> None: self.assertEqual(round(f_Prho.P-P, 5), 0) self.assertEqual(round(f_Prho.T-T, 5), 0) - P = 2 # MPa + P = 2.0 # MPa f_px = IAPWS95_Px(P, 0) f_tx = IAPWS95_Tx(f_px.T, f_px.x) self.assertEqual(round(f_tx.P-P, 5), 0) @@ -2773,7 +2775,7 @@ def test_nh3h2o(self) -> None: # Table 6 x = 0.1 - rhoM = 35 + rhoM = 35.0 M = (1-x)*IAPWS95.M+x*NH3.M rho = rhoM*M st = cl._prop(rho, 600, x) @@ -2785,7 +2787,7 @@ def test_nh3h2o(self) -> None: # self.assertEqual(round(st["w"], 6), 883.925596) x = 0.1 - rhoM = 4 + rhoM = 4.0 M = (1-x)*IAPWS95.M+x*NH3.M rho = rhoM*M st = cl._prop(rho, 600, x) @@ -2795,7 +2797,7 @@ def test_nh3h2o(self) -> None: # self.assertEqual(round(st["w"], 6), 471.762394) x = 0.5 - rhoM = 32 + rhoM = 32.0 M = (1-x)*IAPWS95.M+x*NH3.M rho = rhoM*M st = cl._prop(rho, 500, x) @@ -2805,7 +2807,7 @@ def test_nh3h2o(self) -> None: # self.assertEqual(round(st["w"], 6), 830.295833) x = 0.5 - rhoM = 1 + rhoM = 1.0 M = (1-x)*IAPWS95.M+x*NH3.M rho = rhoM*M st = cl._prop(rho, 500, x) @@ -2815,7 +2817,7 @@ def test_nh3h2o(self) -> None: # self.assertEqual(round(st["w"], 6), 510.258362) x = 0.9 - rhoM = 30 + rhoM = 30.0 M = (1-x)*IAPWS95.M+x*NH3.M rho = rhoM*M st = cl._prop(rho, 400, x) From 909ba5bef439a69e4a4d3d3b32468b1fdeea6f7e Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 22:59:07 -0400 Subject: [PATCH 078/102] More variable name reuse with different types. --- test.py | 66 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/test.py b/test.py index 0f5cc11..9e4ca7f 100755 --- a/test.py +++ b/test.py @@ -244,38 +244,38 @@ def test_ThCond(self) -> None: self.assertEqual(round(_ThCond(0, 873.15)*1000, 7), 79.1034659) # Table 5, pag 10 - fluid = IAPWS95(rho=1, T=647.35) - self.assertEqual(round(fluid.k*1000, 7), 51.9298924) - fluid = IAPWS95(rho=122, T=647.35) - self.assertEqual(round(fluid.k*1000, 6), 130.922885) - fluid = IAPWS95(rho=222, T=647.35) - self.assertEqual(round(fluid.k*1000, 6), 367.787459) - fluid = IAPWS95(rho=272, T=647.35) - self.assertEqual(round(fluid.k*1000, 6), 757.959776) - fluid = IAPWS95(rho=322, T=647.35) - self.assertEqual(round(fluid.k*1000, 5), 1443.75556) - fluid = IAPWS95(rho=372, T=647.35) - self.assertEqual(round(fluid.k*1000, 6), 650.319402) - fluid = IAPWS95(rho=422, T=647.35) - self.assertEqual(round(fluid.k*1000, 6), 448.883487) - fluid = IAPWS95(rho=750, T=647.35) - self.assertEqual(round(fluid.k*1000, 6), 600.961346) + fluid95 = IAPWS95(rho=1, T=647.35) + self.assertEqual(round(fluid95.k*1000, 7), 51.9298924) + fluid95 = IAPWS95(rho=122, T=647.35) + self.assertEqual(round(fluid95.k*1000, 6), 130.922885) + fluid95 = IAPWS95(rho=222, T=647.35) + self.assertEqual(round(fluid95.k*1000, 6), 367.787459) + fluid95 = IAPWS95(rho=272, T=647.35) + self.assertEqual(round(fluid95.k*1000, 6), 757.959776) + fluid95 = IAPWS95(rho=322, T=647.35) + self.assertEqual(round(fluid95.k*1000, 5), 1443.75556) + fluid95 = IAPWS95(rho=372, T=647.35) + self.assertEqual(round(fluid95.k*1000, 6), 650.319402) + fluid95 = IAPWS95(rho=422, T=647.35) + self.assertEqual(round(fluid95.k*1000, 6), 448.883487) + fluid95 = IAPWS95(rho=750, T=647.35) + self.assertEqual(round(fluid95.k*1000, 6), 600.961346) # Industrial formulation, Table 7, 8, 9 - fluid = IAPWS97(T=620, P=20) - self.assertEqual(round(fluid.k*1000, 6), 481.485195) - fluid = IAPWS97(T=620, P=50) - self.assertEqual(round(fluid.k*1000, 6), 545.038940) - fluid = IAPWS97(T=650, P=0.3) - self.assertEqual(round(fluid.k*1000, 7), 52.2311024) - fluid = IAPWS97(T=800, P=50) - self.assertEqual(round(fluid.k*1000, 6), 177.709914) + fluid97 = IAPWS97(T=620, P=20) + self.assertEqual(round(fluid97.k*1000, 6), 481.485195) + fluid97 = IAPWS97(T=620, P=50) + self.assertEqual(round(fluid97.k*1000, 6), 545.038940) + fluid97 = IAPWS97(T=650, P=0.3) + self.assertEqual(round(fluid97.k*1000, 7), 52.2311024) + fluid97 = IAPWS97(T=800, P=50) + self.assertEqual(round(fluid97.k*1000, 6), 177.709914) P = _Region3(T=647.35, rho=222)["P"] - fluid = IAPWS97(T=647.35, P=P) - self.assertEqual(round(fluid.k*1000, 6), 366.879411) + fluid97 = IAPWS97(T=647.35, P=P) + self.assertEqual(round(fluid97.k*1000, 6), 366.879411) P = _Region3(T=647.35, rho=322)["P"] - fluid = IAPWS97(T=647.35, P=P) - self.assertEqual(round(fluid.k*1000, 5), 1241.82415) + fluid97 = IAPWS97(T=647.35, P=P) + self.assertEqual(round(fluid97.k*1000, 5), 1241.82415) def test_Tension(self) -> None: """Selected values from table 1""" @@ -1137,7 +1137,7 @@ def test_IAPWS97_custom(self) -> None: self.assertRaises(NotImplementedError, IAPWS97, **{"P": 65, "s": 9}) self.assertRaises(NotImplementedError, IAPWS97, **{"h": 700, "s": -1}) - def test_IAPWS95_custom(self) -> None: + def test_IAPWS95_custom1(self) -> None: """Cycle input parameter from selected point for IAPWS95""" P = 50.0 # MPa T = 470 # K @@ -1148,6 +1148,8 @@ def test_IAPWS95_custom(self) -> None: self.assertEqual(round(f_hs.P-P, 5), 0) self.assertEqual(round(f_hs.T-T, 5), 0) + def test_IAPWS95_custom2(self) -> None: + """Cycle input parameter from selected point for IAPWS95""" P = 2.0 # MPa f_px = IAPWS95_Px(P, 0.5) f_tx = IAPWS95_Tx(f_px.T, f_px.x) @@ -1236,9 +1238,9 @@ def test_IAPWS95_custom(self) -> None: P = 0.1 # MPa T = 300 # K - f_pt = D2O(P=P, T=T) - self.assertEqual(round(f_pt.P-P, 5), 0) - self.assertEqual(round(f_pt.T-T, 5), 0) + d2o_pt = D2O(P=P, T=T) + self.assertEqual(round(d2o_pt.P-P, 5), 0) + self.assertEqual(round(d2o_pt.T-T, 5), 0) self.assertRaises(NotImplementedError, IAPWS95, **{"T": 700, "x": 0}) self.assertRaises(NotImplementedError, IAPWS95, **{"P": 25, "x": 1}) From 419a3c2723ab59f17e4c09606fdd2ea8ec2bfc81 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 23:05:22 -0400 Subject: [PATCH 079/102] Add missing type annotations. --- iapws/_iapws.py | 2 +- iapws/humidAir.py | 2 +- iapws/iapws08.py | 2 +- iapws/iapws95.py | 2 +- iapws/iapws97.py | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/iapws/_iapws.py b/iapws/_iapws.py index 0c547f9..94297e5 100644 --- a/iapws/_iapws.py +++ b/iapws/_iapws.py @@ -413,7 +413,7 @@ def x(self) -> float: # IAPWS-15 for supercooled liquid water -def _Supercooled(T: float, P: float): +def _Supercooled(T: float, P: float) -> Dict[str, float]: """Guideline on thermodynamic properties of supercooled water Parameters diff --git a/iapws/humidAir.py b/iapws/humidAir.py index d2a417a..409a8aa 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -601,7 +601,7 @@ def __init__(self, **kwargs): self.kwargs = HumidAir.kwargs.copy() self.__call__(**kwargs) - def __call__(self, **kwargs): + def __call__(self, **kwargs) -> None: """Make instance callable to can add input parameter one to one""" # Check alernate input parameters if kwargs.get("v", 0): diff --git a/iapws/iapws08.py b/iapws/iapws08.py index 19bcef8..801ebf5 100644 --- a/iapws/iapws08.py +++ b/iapws/iapws08.py @@ -184,7 +184,7 @@ def __init__(self, **kwargs): self.kwargs = SeaWater.kwargs.copy() self.__call__(**kwargs) - def __call__(self, **kwargs): + def __call__(self, **kwargs) -> None: """Make instance callable to can add input parameter one to one""" self.kwargs.update(kwargs) diff --git a/iapws/iapws95.py b/iapws/iapws95.py index e35c6f6..d42589a 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -444,7 +444,7 @@ def __init__(self, **kwargs): self.kwargs = MEoS.kwargs.copy() self.__call__(**kwargs) - def __call__(self, **kwargs): + def __call__(self, **kwargs) -> None: """Make instance callable to can add input parameter one to one""" # Alternative rho input if "rhom" in kwargs: diff --git a/iapws/iapws97.py b/iapws/iapws97.py index fd39bec..9810afe 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -1871,7 +1871,7 @@ def _Region3(rho: float, T: float) -> Dict[str, float]: return propiedades -def _h_3ab(P): +def _h_3ab(P: float) -> float: """Define the boundary between Region 3a-3b, h=f(P) Parameters @@ -4334,7 +4334,7 @@ def __init__(self, **kwargs): self.kwargs = IAPWS97.kwargs.copy() self.__call__(**kwargs) - def __call__(self, **kwargs): + def __call__(self, **kwargs) -> None: """Invoke the solver.""" self.kwargs.update(kwargs) From e72fb414cc11ded05011eeba66ab688b91bf03e0 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 23:21:54 -0400 Subject: [PATCH 080/102] Silly flake8 rule about double spaces. --- test.py | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/test.py b/test.py index 9e4ca7f..fabcf80 100755 --- a/test.py +++ b/test.py @@ -852,8 +852,8 @@ def test_IAPWS97_5(self) -> None: def test_IAPWS97_custom(self) -> None: """Cycle input parameter from selected point for IAPWS97""" # Region 1 - P = 50.0 # MPa - T = 470 # K + P = 50.0 # MPa + T = 470 # K f_pt = IAPWS97(P=P, T=T) f_ph = IAPWS97(h=f_pt.h, P=f_pt.P) f_ps = IAPWS97(P=f_ph.P, s=f_ph.s) @@ -861,8 +861,8 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_hs.P-P, 6), 0) self.assertEqual(round(f_hs.T-T, 6), 0) - P = 20.0 # MPa - T = 370 # K + P = 20.0 # MPa + T = 370 # K f_pt = IAPWS97(P=P, T=T) f_ph = IAPWS97(h=f_pt.h, P=f_pt.P) f_ps = IAPWS97(P=f_ph.P, s=f_ph.s) @@ -871,8 +871,8 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_hs.T-T, 6), 0) # Region 2 - P = 25.0 # MPa - T = 700 # K + P = 25.0 # MPa + T = 700 # K f_pt = IAPWS97(P=P, T=T) f_ph = IAPWS97(h=f_pt.h, P=f_pt.P) f_ps = IAPWS97(P=f_ph.P, s=f_ph.s) @@ -880,8 +880,8 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_hs.P-P, 6), 0) self.assertEqual(round(f_hs.T-T, 6), 0) - P = 10.0 # MPa - T = 700 # K + P = 10.0 # MPa + T = 700 # K f_pt = IAPWS97(P=P, T=T) f_ph = IAPWS97(h=f_pt.h, P=f_pt.P) f_ps = IAPWS97(P=f_ph.P, s=f_ph.s) @@ -917,8 +917,8 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_hs.T-T, 6), 0) # Region 3 - P = 50.0 # MPa - T = 700 # K + P = 50.0 # MPa + T = 700 # K f_pt = IAPWS97(P=P, T=T) f_ph = IAPWS97(h=f_pt.h, P=f_pt.P) f_ps = IAPWS97(P=f_ph.P, s=f_ph.s) @@ -926,8 +926,8 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_hs.P-P, 6), 0) self.assertEqual(round(f_hs.T-T, 6), 0) - P = 20.0 # MPa - s = 4 # kJ/kgK + P = 20.0 # MPa + s = 4 # kJ/kgK f_ps = IAPWS97(P=P, s=s) f_ph = IAPWS97(h=f_pt.h, P=f_pt.P) f_pt = IAPWS97(P=f_ph.P, T=f_ph.T) @@ -935,35 +935,35 @@ def test_IAPWS97_custom(self) -> None: self.assertEqual(round(f_hs.P-P, 6), 0) self.assertEqual(round(f_hs.s-s, 6), 0) - P = 19.0 # MPa + P = 19.0 # MPa f_px = IAPWS97(P=P, x=0) f_tx = IAPWS97(T=f_px.T, x=f_px.x) self.assertEqual(round(f_tx.P-P, 3), 0) self.assertEqual(round(f_tx.x, 6), 0) - P = 19.0 # MPa + P = 19.0 # MPa f_px = IAPWS97(P=P, x=1) f_tx = IAPWS97(T=f_px.T, x=f_px.x) self.assertEqual(round(f_tx.P-P, 3), 0) self.assertEqual(round(f_tx.x, 6), 1) - P = 21.0 # MPa + P = 21.0 # MPa f_px = IAPWS97(P=P, x=1) f_tx = IAPWS97(T=f_px.T, x=f_px.x) self.assertEqual(round(f_tx.P-P, 2), 0) self.assertEqual(round(f_tx.x, 3), 1) - P = 21.5 # MPa + P = 21.5 # MPa f_px = IAPWS97(P=P, x=0) f_tx = IAPWS97(T=f_px.T, x=f_px.x) self.assertEqual(round(f_tx.P-P, 2), 0) self.assertEqual(round(f_tx.x, 3), 0) - P = 21.5 # MPa + P = 21.5 # MPa f_px = IAPWS97(P=P, x=1) f_tx = IAPWS97(T=f_px.T, x=f_px.x) self.assertEqual(round(f_tx.P-P, 2), 0) self.assertEqual(round(f_tx.x, 3), 1) - P = 22.02 # MPa + P = 22.02 # MPa f_px = IAPWS97(P=P, x=0) f_tx = IAPWS97(T=f_px.T, x=f_px.x) self.assertEqual(round(f_tx.P-P, 2), 0) @@ -1139,8 +1139,8 @@ def test_IAPWS97_custom(self) -> None: def test_IAPWS95_custom1(self) -> None: """Cycle input parameter from selected point for IAPWS95""" - P = 50.0 # MPa - T = 470 # K + P = 50.0 # MPa + T = 470 # K f_pt = IAPWS95_PT(P, T) f_ph = IAPWS95_Ph(f_pt.P, f_pt.h) f_ps = IAPWS95_Ps(f_ph.P, f_ph.s) @@ -1150,7 +1150,7 @@ def test_IAPWS95_custom1(self) -> None: def test_IAPWS95_custom2(self) -> None: """Cycle input parameter from selected point for IAPWS95""" - P = 2.0 # MPa + P = 2.0 # MPa f_px = IAPWS95_Px(P, 0.5) f_tx = IAPWS95_Tx(f_px.T, f_px.x) f_tv = IAPWS95(T=f_px.T, v=f_px.v) @@ -1170,8 +1170,8 @@ def test_IAPWS95_custom2(self) -> None: self.assertEqual(round(f_Prho.P-P, 5), 0) self.assertEqual(round(f_Prho.x-0.5, 5), 0) - P = 50.0 # MPa - T = 770 # K + P = 50.0 # MPa + T = 770 # K f_pt = IAPWS95_PT(P, T) f_tv = IAPWS95(T=f_pt.T, v=f_pt.v) f_th = IAPWS95(T=f_tv.T, h=f_tv.h) @@ -1190,7 +1190,7 @@ def test_IAPWS95_custom2(self) -> None: self.assertEqual(round(f_Prho.P-P, 5), 0) self.assertEqual(round(f_Prho.T-T, 5), 0) - P = 0.1 # MPa + P = 0.1 # MPa T = 300 # K f_pt = IAPWS95_PT(P, T) f_tv = IAPWS95(T=f_pt.T, v=f_pt.v) @@ -1210,7 +1210,7 @@ def test_IAPWS95_custom2(self) -> None: self.assertEqual(round(f_Prho.P-P, 5), 0) self.assertEqual(round(f_Prho.T-T, 5), 0) - P = 0.1 # MPa + P = 0.1 # MPa T = 500 # K f_pt = IAPWS95_PT(P, T) f_tv = IAPWS95(T=f_pt.T, v=f_pt.v) @@ -1228,7 +1228,7 @@ def test_IAPWS95_custom2(self) -> None: self.assertEqual(round(f_Prho.P-P, 5), 0) self.assertEqual(round(f_Prho.T-T, 5), 0) - P = 2.0 # MPa + P = 2.0 # MPa f_px = IAPWS95_Px(P, 0) f_tx = IAPWS95_Tx(f_px.T, f_px.x) self.assertEqual(round(f_tx.P-P, 5), 0) @@ -1236,7 +1236,7 @@ def test_IAPWS95_custom2(self) -> None: f_tx = IAPWS95_Tx(f_px.T, f_px.x) self.assertEqual(round(f_tx.P-P, 5), 0) - P = 0.1 # MPa + P = 0.1 # MPa T = 300 # K d2o_pt = D2O(P=P, T=T) self.assertEqual(round(d2o_pt.P-P, 5), 0) From a48c4d177c2424ed2fa3036f626046c4d8de976a Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 23:25:29 -0400 Subject: [PATCH 081/102] Missing return type annotation. --- iapws/iapws97.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iapws/iapws97.py b/iapws/iapws97.py index 9810afe..9f98c00 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -4687,7 +4687,7 @@ def rho_funcion(rho: float) -> float: self.Hvap = vapor["h"]-liquido["h"] self.Svap = vapor["s"]-liquido["s"] - def fill(self, fase: _fase, estado: Dict[str, float]): + def fill(self, fase: _fase, estado: Dict[str, float]) -> None: """Fill phase properties""" fase.v = estado["v"] fase.rho = 1/fase.v From 683259acff3b12b978be9f58bbc8f8c24917b8ea Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 23:25:50 -0400 Subject: [PATCH 082/102] Annotate the documentation function decorator. --- iapws/iapws95.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/iapws/iapws95.py b/iapws/iapws95.py index d42589a..0955a5f 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -14,7 +14,7 @@ import platform import warnings from math import exp, log -from typing import Tuple, Dict, Optional, List +from typing import Tuple, Dict, Optional, List, Callable, Any from scipy.optimize import fsolve @@ -2313,17 +2313,18 @@ def _dPdT_sat(cls, T: float) -> float: return dPdT -def mainClassDoc(): +def mainClassDoc() -> Callable[[Callable[..., Any]], Callable[..., Any]]: """ Function decorator used to automatic adiction of base class MEoS in subclass __doc__ """ - def decorator(f): + def decorator(f: Callable[..., Any]) -> Callable[..., Any]: # __doc__ is only writable in python3. # The doc build must be done with python3 so this snippet do the work py_version = platform.python_version() if py_version[0] == "3": - doc = f.__doc__.split(os.linesep) + if isinstance(f.__doc__, str): + doc = f.__doc__.split(os.linesep) try: ind = doc.index("") except ValueError: @@ -2331,7 +2332,8 @@ def decorator(f): doc1 = os.linesep.join(doc[:ind]) doc3 = os.linesep.join(doc[ind:]) - doc2 = os.linesep.join(MEoS.__doc__.split(os.linesep)[3:]) + if isinstance(MEoS.__doc__, str): + doc2 = os.linesep.join(MEoS.__doc__.split(os.linesep)[3:]) f.__doc__ = doc1 + os.linesep + os.linesep + \ doc2 + os.linesep + os.linesep + doc3 From 153829467980915a12898ad5d01fdca2e03b9446 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Tue, 16 Mar 2021 23:34:43 -0400 Subject: [PATCH 083/102] Enable type checking on calculo(). --- iapws/iapws08.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/iapws/iapws08.py b/iapws/iapws08.py index 801ebf5..2a2d748 100644 --- a/iapws/iapws08.py +++ b/iapws/iapws08.py @@ -181,6 +181,14 @@ def __init__(self, **kwargs): self.gtp = float('nan') self.gpp = float('nan') + self.k: Optional[float] = None + self.sigma: Optional[float] = None + self.mu: Optional[float] = None + self.muw: Optional[float] = None + self.mus: Optional[float] = None + self.osm: Optional[float] = None + self.haline: Optional[float] = None + self.kwargs = SeaWater.kwargs.copy() self.__call__(**kwargs) @@ -194,16 +202,19 @@ def __call__(self, **kwargs) -> None: self.calculo() self.msg = "" - def calculo(self): + def calculo(self) -> None: """Calculate procedure""" - T = self.kwargs["T"] - P = self.kwargs["P"] - S = self.kwargs["S"] + assert(self.kwargs["P"] is not None) + assert(self.kwargs["T"] is not None) + assert(self.kwargs["S"] is not None) + T = float(self.kwargs["T"]) + P = float(self.kwargs["P"]) + S = float(self.kwargs["S"]) self.m = S/(1-S)/Ms - if self.kwargs["fast"] and T <= 313.15: + if bool(self.kwargs["fast"]) and T <= 313.15: pw = self._waterSupp(T, P) - elif self.kwargs["IF97"]: + elif bool(self.kwargs["IF97"]): pw = self._waterIF97(T, P) else: pw = self._water(T, P) From b22a9551fdf6f5530cf6debe3bd2406317aacca8 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Wed, 17 Mar 2021 01:02:37 -0400 Subject: [PATCH 084/102] Enable type checking in calculo. --- iapws/iapws97.py | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/iapws/iapws97.py b/iapws/iapws97.py index 9f98c00..efdb726 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -3570,7 +3570,7 @@ def _Backward3x_v_PT(T: float, P: float, x: str) -> float: # Region 4 -def _Region4(P: float, x: float) -> Dict[str, Optional[float]]: +def _Region4(P: float, x: float) -> Dict[str, float]: """Basic equation for region 4 Parameters @@ -3602,17 +3602,17 @@ def _Region4(P: float, x: float) -> Dict[str, Optional[float]]: P1 = _Region1(T, P) P2 = _Region2(T, P) - propiedades: Dict[str, Optional[float]] = {} + propiedades: Dict[str, float] = {} propiedades["T"] = T propiedades["P"] = P propiedades["v"] = P1["v"]+x*(P2["v"]-P1["v"]) propiedades["h"] = P1["h"]+x*(P2["h"]-P1["h"]) propiedades["s"] = P1["s"]+x*(P2["s"]-P1["s"]) - propiedades["cp"] = None - propiedades["cv"] = None - propiedades["w"] = None - propiedades["alfav"] = None - propiedades["kt"] = None + #propiedades["cp"] = None + #propiedades["cv"] = None + #propiedades["w"] = None + #propiedades["alfav"] = None + #propiedades["kt"] = None propiedades["region"] = 4 propiedades["x"] = x return propiedades @@ -4331,6 +4331,18 @@ class IAPWS97(_fase): msg = "Unknown variables" def __init__(self, **kwargs): + self.v0: Optional[float] = None + self.h0: Optional[float] = None + self.u0: Optional[float] = None + self.s0: Optional[float] = None + self.a0: Optional[float] = None + self.g0: float = 0.0 + + self.cp0: Optional[float] = None + self.cv0: Optional[float] = None + self.cp0_cv: Optional[float] = None + self.w0: Optional[float] = None + self.gamma0: Optional[float] = None self.kwargs = IAPWS97.kwargs.copy() self.__call__(**kwargs) @@ -4366,10 +4378,12 @@ def calculable(self) -> str: self._thermo = "Px" return self._thermo - def calculo(self): + def calculo(self) -> None: """Calculate procedure""" - propiedades = None - args = (self.kwargs[self._thermo[0]], self.kwargs[self._thermo[1]]) + propiedades: Dict[str, float] = {} + arg1: float = self.kwargs[self._thermo[0]] # type: ignore + arg2: float = self.kwargs[self._thermo[1]] # type: ignore + args = (arg1, arg2) if self._thermo == "TP": T, P = args region = _Bound_TP(T, P) @@ -4577,7 +4591,7 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: elif Ps_623 < P < Pc and x in (0, 1): def rho_funcion(rho: float) -> float: return _Region3(rho, T)["P"]-P - rhoo = 1./_Backward3_sat_v_P(P, T, x) + rhoo = 1./_Backward3_sat_v_P(P, T, int(x)) rho = float(fsolve(rho_funcion, rhoo)[0]) propiedades = _Region3(rho, T) elif P == Pc and 0 <= x <= 1: @@ -4597,7 +4611,7 @@ def rho_funcion(rho: float) -> float: elif 273.15 <= T <= 623.15 and x == 1: propiedades = _Region2(T, P) elif 623.15 < T < Tc and x in (0, 1): - rho = 1./_Backward3_sat_v_P(P, T, x) + rho = 1./_Backward3_sat_v_P(P, T, int(x)) propiedades = _Region3(rho, T) elif T == Tc and 0 <= x <= 1: propiedades = _Region3(rhoc, Tc) @@ -4616,7 +4630,7 @@ def rho_funcion(rho: float) -> float: self.dipole = Dipole self.x = propiedades["x"] - self.region = propiedades["region"] + self.region = int(propiedades["region"]) self.name = "water" self.synonim = "R-718" self.CAS = "7732-18-5" From a8d3b1b7ec2edefd7b30bfae3e0892d128f3db55 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Wed, 17 Mar 2021 01:21:38 -0400 Subject: [PATCH 085/102] Import missing optional keyword. --- iapws/iapws08.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iapws/iapws08.py b/iapws/iapws08.py index 2a2d748..17dd880 100644 --- a/iapws/iapws08.py +++ b/iapws/iapws08.py @@ -21,7 +21,7 @@ from __future__ import division from math import exp, log import warnings -from typing import Dict, Tuple +from typing import Dict, Tuple, Optional from scipy.optimize import fsolve From 3abe905c6cf7952292a54c65ac5042c2aff4cf9e Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Wed, 17 Mar 2021 01:22:01 -0400 Subject: [PATCH 086/102] Enable type checking in IAPWS95.calculo. --- iapws/iapws95.py | 30 +++++++++++++++++++----------- test.py | 6 ++++++ 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 0955a5f..007152c 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -424,6 +424,8 @@ class MEoS(_fase): rhoc: float Tc: float Pc: float + Tt: float + _constant_R: float _constants: Dict[str, List[float]] def __init__(self, **kwargs): @@ -439,6 +441,10 @@ def __init__(self, **kwargs): assert(isinstance(self._rhoG_exp, list)) assert(isinstance(self.M, float)) + self.sigma: Optional[float] = None + self.Hvap: Optional[float] = None + self.Svap: Optional[float] = None + self.R = self.__class__._constant_R/self.M self.Zc = self.Pc/self.rhoc/self.R/self.Tc self.kwargs = MEoS.kwargs.copy() @@ -519,23 +525,25 @@ def calculable(self) -> bool: self._mode = "Px" return bool(self._mode) - def calculo(self): + def calculo(self) -> None: """Calculate procedure""" - T = self.kwargs["T"] - rho = self.kwargs["rho"] - P = self.kwargs["P"] - s = self.kwargs["s"] - h = self.kwargs["h"] - u = self.kwargs["u"] - x = self.kwargs["x"] + T: float = self.kwargs["T"] # type: ignore + rho: float = self.kwargs["rho"] # type: ignore + P: float = self.kwargs["P"] # type: ignore + s: float = self.kwargs["s"] # type: ignore + h: float = self.kwargs["h"] # type: ignore + u: float = self.kwargs["u"] # type: ignore + x: float = self.kwargs["x"] # type: ignore # Initial values T0 = self.kwargs["T0"] rho0 = self.kwargs["rho0"] if T0 or rho0: - To = T0 - rhoo = rho0 + if T0 is not None: + To = float(T0) + if rho0 is not None: + rhoo = float(rho0) elif self.name == "air": To = 300 rhoo = 1e-3 @@ -557,7 +565,7 @@ def calculo(self): rhoc = self._constants.get("rhoref", [self.rhoc])[0] Tc = self._constants.get("Tref", [self.Tc])[0] - propiedades = None + propiedades: Dict[str, float] = {} if self._mode not in ("Tx", "Px"): # Method with iteration necessary to get x diff --git a/test.py b/test.py index fabcf80..aae02c8 100755 --- a/test.py +++ b/test.py @@ -2673,6 +2673,7 @@ def test_Ammonia(self) -> None: self.assertEqual(round(st.Liquid.rho, 2), 732.90) self.assertEqual(round(st.Gas.rho, 4), 0.0641) # self.assertEqual(round(st.Liquid.h, 2), -143.14) + assert(st.Hvap is not None) self.assertEqual(round(st.Hvap, 1), 1484.4) self.assertEqual(round(st.Gas.h, 1), 1341.2) self.assertEqual(round(st.Liquid.s, 4), -0.4715) @@ -2684,9 +2685,11 @@ def test_Ammonia(self) -> None: self.assertEqual(round(st.Liquid.rho, 2), 638.57) self.assertEqual(round(st.Gas.rho, 4), 3.4567) self.assertEqual(round(st.Liquid.h, 2), 200.00) + assert(st.Hvap is not None) self.assertEqual(round(st.Hvap, 1), 1262.2) self.assertEqual(round(st.Gas.h, 1), 1462.2) self.assertEqual(round(st.Liquid.s, 4), 1.0000) + assert(st.Svap is not None) self.assertEqual(round(st.Svap, 4), 4.6210) self.assertEqual(round(st.Gas.s, 4), 5.6210) @@ -2695,9 +2698,11 @@ def test_Ammonia(self) -> None: self.assertEqual(round(st.Liquid.rho, 2), 357.80) self.assertEqual(round(st.Gas.rho, 2), 120.73) self.assertEqual(round(st.Liquid.h, 2), 919.68) + assert(st.Hvap is not None) self.assertEqual(round(st.Hvap, 2), 389.44) self.assertEqual(round(st.Gas.h, 1), 1309.1) self.assertEqual(round(st.Liquid.s, 4), 3.0702) + assert(st.Svap is not None) self.assertEqual(round(st.Svap, 4), 0.9781) self.assertEqual(round(st.Gas.s, 4), 4.0483) @@ -2706,6 +2711,7 @@ def test_Ammonia(self) -> None: self.assertEqual(round(st.Liquid.rho, 2), 602.92) # self.assertEqual(round(st.Gas.rho, 4), 7.7821) self.assertEqual(round(st.Liquid.h, 2), 317.16) + assert(st.Hvap is not None) self.assertEqual(round(st.Hvap, 1), 1166.2) self.assertEqual(round(st.Gas.h, 1), 1483.4) self.assertEqual(round(st.Liquid.s, 4), 1.4072) From 30d9a0d7110ec05e5add1bb5fd32b66f6a0dae63 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Wed, 17 Mar 2021 01:32:52 -0400 Subject: [PATCH 087/102] Consequences of having Optional in iapws08.py on test.py --- test.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test.py b/test.py index aae02c8..68f843e 100755 --- a/test.py +++ b/test.py @@ -1577,6 +1577,7 @@ def test_SeaWater(self) -> None: self.assertEqual(round(fluid.rho, 5), 1028.10720) self.assertEqual(round(fluid.cp, 8), 3.98648579) self.assertEqual(round(fluid.w, 5), 1449.00246) + assert(fluid.muw is not None) self.assertEqual(round(fluid.muw, 8), -2.25047137) # Part b, pag 18 @@ -1616,6 +1617,7 @@ def test_SeaWater(self) -> None: self.assertEqual(round(fluid.rho, 5), 1029.85888) self.assertEqual(round(fluid.cp, 8), 3.74507355) self.assertEqual(round(fluid.w, 5), 3961.27835) + assert(fluid.muw is not None) self.assertEqual(round(fluid.muw, 7), -54.7200505) # Part c, pag 19 @@ -1655,6 +1657,7 @@ def test_SeaWater(self) -> None: self.assertEqual(round(fluid.rho, 5), 1070.92645) self.assertEqual(round(fluid.cp, 8), 3.77190387) self.assertEqual(round(fluid.w, 5), 1621.98998) + assert(fluid.muw is not None) self.assertEqual(round(fluid.muw, 7), 95.3214082) # Custom derivative implementation @@ -1749,6 +1752,7 @@ def test_SeaWaterIF97(self) -> None: self.assertEqual(round(fluid.s, 12), -0.68447e-7) self.assertEqual(round(fluid.cp, 8), 0.398647132e1) self.assertEqual(round(fluid.w, 5), 0.144907123e4) + assert(fluid.muw is not None) self.assertEqual(round(fluid.muw, 8), -0.225045466e1) fluid = SeaWater(T=353, P=0.101325, S=0.1, IF97=True) @@ -1786,6 +1790,7 @@ def test_SeaWaterIF97(self) -> None: self.assertEqual(round(fluid.s, 9), 0.917342513) self.assertEqual(round(fluid.cp, 8), 0.374382192e1) self.assertEqual(round(fluid.w, 5), 0.401505044e4) + assert(fluid.muw is not None) self.assertEqual(round(fluid.muw, 7), -0.547176899e2) # Part c, pag 19 @@ -1824,6 +1829,7 @@ def test_SeaWaterIF97(self) -> None: self.assertEqual(round(fluid.s, 10), -0.161227439e-1) self.assertEqual(round(fluid.cp, 8), 0.377237430e1) self.assertEqual(round(fluid.w, 5), 0.162218081e4) + assert(fluid.muw is not None) self.assertEqual(round(fluid.muw, 7), 0.953212423e2) # Table A2 @@ -1947,38 +1953,47 @@ def test_SeaWater_thcond(self) -> None: """Table 2, pag 5""" fluid = SeaWater(T=293.15, P=0.1, S=0.035) self.assertEqual(round(_ThCond_SeaWater(T=293.15, P=0.1, S=0.035), 9), -0.004186040) + assert(fluid.k is not None) self.assertEqual(round(fluid.k, 9), 0.593825535) fluid = SeaWater(T=293.15, P=120, S=0.035) self.assertEqual(round(_ThCond_SeaWater(T=293.15, P=120, S=0.035), 9), -0.004317350) + assert(fluid.k is not None) self.assertEqual(round(fluid.k, 9), 0.651692949) fluid = SeaWater(T=333.15, P=0.1, S=0.035) self.assertEqual(round(_ThCond_SeaWater(T=333.15, P=0.1, S=0.035), 9), -0.004124057) + assert(fluid.k is not None) self.assertEqual(round(fluid.k, 9), 0.646875533) fluid = SeaWater(T=333.15, P=120, S=0.035) self.assertEqual(round(_ThCond_SeaWater(T=333.15, P=120, S=0.035), 9), -0.004264405) + assert(fluid.k is not None) self.assertEqual(round(fluid.k, 9), 0.702484548) fluid = SeaWater(T=293.15, P=0.1, S=0.1) self.assertEqual(round(_ThCond_SeaWater(T=293.15, P=0.1, S=0.1), 9), -0.013819821) + assert(fluid.k is not None) self.assertEqual(round(fluid.k, 9), 0.584191754) fluid = SeaWater(T=373.15, P=1, S=0.1) self.assertEqual(round(_ThCond_SeaWater(T=373.15, P=1, S=0.1), 9), -0.013094107) + assert(fluid.k is not None) self.assertEqual(round(fluid.k, 9), 0.664627314) fluid = SeaWater(T=293.15, P=0.1, S=0.12) self.assertEqual(round(_ThCond_SeaWater(T=293.15, P=0.1, S=0.12), 9), -0.017005302) + assert(fluid.k is not None) self.assertEqual(round(fluid.k, 9), 0.581006273) fluid = SeaWater(T=293.15, P=120, S=0.12) self.assertEqual(round(_ThCond_SeaWater(T=293.15, P=120, S=0.12), 9), -0.020194816) + assert(fluid.k is not None) self.assertEqual(round(fluid.k, 9), 0.635815483) fluid = SeaWater(T=333.15, P=120, S=0.12) self.assertEqual(round(_ThCond_SeaWater(T=333.15, P=120, S=0.12), 9), -0.019722469) + assert(fluid.k is not None) self.assertEqual(round(fluid.k, 9), 0.687026483) fluid = SeaWater(T=270, P=1, S=0.12) From ac85094813d759d9df76a63de68946d54614f9fd Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Wed, 17 Mar 2021 21:31:56 -0400 Subject: [PATCH 088/102] Class hierarchy clarity improvements. It's now clearer to me how _fase is initialized. Document the origin of M and name in MEoS more clearly. --- iapws/_utils.py | 167 +++++++++++++++++++++++----------------------- iapws/ammonia.py | 3 + iapws/humidAir.py | 7 ++ iapws/iapws08.py | 1 + iapws/iapws95.py | 9 +++ iapws/iapws97.py | 1 + 6 files changed, 106 insertions(+), 82 deletions(-) diff --git a/iapws/_utils.py b/iapws/_utils.py index ae49bdd..8dce5b7 100644 --- a/iapws/_utils.py +++ b/iapws/_utils.py @@ -63,88 +63,91 @@ def getphase(Tc: float, Pc: float, T: float, P: float, x: float, region: int) -> class _fase(object): - """Class to implement a null phase""" - - # The name of the substance. - # Set in NH3, Air, IAPWS95, D2O, and IAPWS97. - name: str = "unknown" - - # One always computed form the other - v: float = float('nan') - rho: float = float('nan') - - h: float = float('nan') - s: float = float('nan') - - cv: float = float('nan') - alfap: float = float('nan') - betap: float = float('nan') - cp: float = float('nan') - kappa: float = float('nan') - alfav: float = float('nan') - - g: float = float('nan') - fi: float = float('nan') - - w: float = float('nan') - Z: float = float('nan') - - drhodP_T: float = float('nan') - mu: float = float('nan') - cp_cv: float = float('nan') - k: float = float('nan') - - epsilon: Optional[float] = None - n: Optional[float] = None - - # -------------------------------------------- - # Calculated identically between 95 and 97 - u: float = float('nan') - a: float = float('nan') - nu: float = float('nan') - Prandt: float = float('nan') - alfa: float = float('nan') - f: float = float('nan') - - # Calculated similarly, but not identically? - joule: float = float('nan') - gamma: float = float('nan') - deltat: float = float('nan') - - # Calculated on 95 only from earlier variables and self.M - rhoM: float = float('nan') - M: float = float('nan') - hM: float = float('nan') - sM: float = float('nan') - uM: float = float('nan') - aM: float = float('nan') - gM: float = float('nan') - cvM: float = float('nan') - cpM: float = float('nan') - Z_rho: float = float('nan') - - # Derivatives calculated only in IAPWS95 - dpdT_rho: float = float('nan') - dpdrho_T: float = float('nan') - drhodT_P: float = float('nan') - dhdT_rho: float = float('nan') - dhdT_P: float = float('nan') - dhdrho_T: float = float('nan') - dhdrho_P: float = float('nan') - dhdP_T: float = float('nan') - dhdP_rho: float = float('nan') - kt: float = float('nan') - ks: float = float('nan') - Ks: float = float('nan') - Kt: float = float('nan') - betas: float = float('nan') - Gruneisen: float = float('nan') - IntP: float = float('nan') - hInput: float = float('nan') - - # Properties added because various methods set/access them? - xkappa: float = float('nan') - kappas: float = float('nan') + """ + Class to implement a null phase. + + IAPWS95 and IAPWS97 both implement Liquid and Gas/Vapor phasee in + addition to being phases themselves. Confusingly minor + differences between derived classes impose different constraints + on this class. + """ + + def __init__(self) -> None: + # One always computed form the other + self.v = float('nan') + self.rho = float('nan') + + self.h = float('nan') + self.s = float('nan') + + self.cv = float('nan') + self.alfap = float('nan') + self.betap = float('nan') + self.cp = float('nan') + self.kappa = float('nan') + self.alfav = float('nan') + + self.g = float('nan') + self.fi = float('nan') + + self.w = float('nan') + self.Z = float('nan') + + self.drhodP_T = float('nan') + self.mu = float('nan') + self.cp_cv = float('nan') + self.k = float('nan') + + self.epsilon: Optional[float] = None + self.n: Optional[float] = None + + # -------------------------------------------- + # Calculated identically between 95 and 97 + self.u = float('nan') + self.a = float('nan') + self.nu = float('nan') + self.Prandt = float('nan') + self.alfa = float('nan') + self.f = float('nan') + + # Calculated similarly, but not identically? + self.joule = float('nan') + self.gamma = float('nan') + self.deltat = float('nan') + + # Calculated on 95 only from earlier variables and self.M + self.rhoM = float('nan') + self.hM = float('nan') + self.sM = float('nan') + self.uM = float('nan') + self.aM = float('nan') + self.gM = float('nan') + self.cvM = float('nan') + self.cpM = float('nan') + self.Z_rho = float('nan') + + # Derivatives calculated only in IAPWS95 + self.dpdT_rho = float('nan') + self.dpdrho_T = float('nan') + self.drhodT_P = float('nan') + self.dhdT_rho = float('nan') + self.dhdT_P = float('nan') + self.dhdrho_T = float('nan') + self.dhdrho_P = float('nan') + self.dhdP_T = float('nan') + self.dhdP_rho = float('nan') + self.kt = float('nan') + self.ks = float('nan') + self.Ks = float('nan') + self.Kt = float('nan') + self.betas = float('nan') + self.Gruneisen = float('nan') + self.IntP = float('nan') + self.hInput = float('nan') + + # Properties added because various methods set/access them? + self.xkappa = float('nan') + self.kappas = float('nan') def deriv_H(state: Any, z: str, x: str, y: str, fase: _fase) -> float: diff --git a/iapws/ammonia.py b/iapws/ammonia.py index f1fa7c5..8b44b10 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -84,6 +84,9 @@ class NH3(MEoS): _rhoG_ao = [-.38435, -4.0846, -6.6634, -0.31881e2, 0.21306e3, -0.24648e3] _rhoG_exp = [0.218, 0.55, 1.5, 3.7, 5.5, 5.8] + def __init__(self, **kwargs): + super().__init__(**kwargs) + # fase is unused def _visco(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: """Equation for the Viscosity diff --git a/iapws/humidAir.py b/iapws/humidAir.py index 409a8aa..caabfc0 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -230,6 +230,9 @@ class MEoSBlend(MEoS): _blend: Dict[str, Any] + def __init__(self, **kwargs): + super().__init__(**kwargs) + @classmethod def _dewP(cls, T: float) -> float: """Using ancillary equation return the pressure of dew point""" @@ -339,6 +342,9 @@ class Air(MEoSBlend): _rhoG_ao = [-0.20466e1, -0.4752e1, -0.13259e2, -0.47652e2] _rhoG_exp = [0.41, 1.0, 2.8, 6.5] + def __init__(self, **kwargs): + super().__init__(**kwargs) + @classmethod def _Liquid_Density(cls, T: float) -> float: """Auxiliary equation for the density or saturated liquid @@ -598,6 +604,7 @@ class HumidAir(_fase): def __init__(self, **kwargs): """Constructor, define common constant and initinialice kwargs""" + super().__init__() self.kwargs = HumidAir.kwargs.copy() self.__call__(**kwargs) diff --git a/iapws/iapws08.py b/iapws/iapws08.py index 17dd880..6a299d9 100644 --- a/iapws/iapws08.py +++ b/iapws/iapws08.py @@ -173,6 +173,7 @@ class SeaWater(_fase): def __init__(self, **kwargs): """Constructor, initinialice kwargs""" + super().__init__() self.gs = float('nan') self.gt = float('nan') self.gp = float('nan') diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 007152c..92b70b6 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -427,9 +427,15 @@ class MEoS(_fase): Tt: float _constant_R: float _constants: Dict[str, List[float]] + M: float + # The name of the substance. + # Set in NH3, Air, IAPWS95, D2O, and IAPWS97. + name: str def __init__(self, **kwargs): """Constructor, define common constant and initinialice kwargs""" + super().__init__() + # These class variables must be defined by the subclass. assert(isinstance(self._Pv_ao, list)) assert(isinstance(self._Pv_exp, list)) @@ -2544,6 +2550,9 @@ class IAPWS95(MEoS): -63.9201063] _rhoG_exp = [1.0, 2.0, 4.0, 9.0, 18.5, 35.5] + def __init__(self, **kwargs): + super().__init__(**kwargs) + def _phi0(self, tau: float, delta: float) -> Dict[str, float]: """Low temperature extension of the IAPWS-95""" prop = MEoS._phi0(self, tau, delta) diff --git a/iapws/iapws97.py b/iapws/iapws97.py index efdb726..aab395b 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -4331,6 +4331,7 @@ class IAPWS97(_fase): msg = "Unknown variables" def __init__(self, **kwargs): + super().__init__() self.v0: Optional[float] = None self.h0: Optional[float] = None self.u0: Optional[float] = None From 4bfe7057dfa7772fe069d8dd51710ba668111253 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Wed, 17 Mar 2021 22:56:35 -0400 Subject: [PATCH 089/102] Improve static typing with a custom class instead of a dictionary. It's much more difficult to have a static assurances of the keys and values of a dictionary than a custom class. The resulting variable names are slightly different, but not obviously worse to me. More importantly, the type is differentiated from alll other dictionaries that are keyed by str and have float values, of which there are several, including some with overlapping keys (e.g. _fav). --- iapws/_utils.py | 13 +++ iapws/ammonia.py | 14 +-- iapws/humidAir.py | 26 +++--- iapws/iapws95.py | 221 +++++++++++++++------------------------------- test.py | 200 ++++++++++++++++++++--------------------- 5 files changed, 204 insertions(+), 270 deletions(-) diff --git a/iapws/_utils.py b/iapws/_utils.py index 8dce5b7..980d55e 100644 --- a/iapws/_utils.py +++ b/iapws/_utils.py @@ -233,6 +233,19 @@ def deriv_H(state: Any, z: str, x: str, y: str, fase: _fase) -> float: return mul*deriv +class HelmholtzDerivatives(object): + """Helmholtz free energy and derivatives.""" + + def __init__(self, fi: float, fit: float, fid: float, + fitt: float, fidd: float, fidt: float) -> None: + self.fi = fi + self.fit = fit + self.fid = fid + self.fitt = fitt + self.fidd = fidd + self.fidt = fidt + + def deriv_G(state: Any, z: str, x: str, y: str, fase: _fase) -> float: r"""Calculate generic partial derivative :math:`\left.\frac{\partial z}{\partial x}\right|_{y}` from a fundamental diff --git a/iapws/ammonia.py b/iapws/ammonia.py index 8b44b10..055ee5c 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -449,13 +449,13 @@ def _phir(self, rho: float, T: float, x: float) -> Dict[str, float]: prop = {} prop["tau"] = tau prop["delta"] = delta - prop["fir"] = (1-x)*phi1["fir"] + x*phi2["fir"] + Dphi["fir"] - prop["firt"] = (1-x)*phi1["firt"] + x*phi2["firt"] + Dphi["firt"] - prop["firtt"] = (1-x)*phi1["firtt"] + x*phi2["firtt"] + Dphi["firtt"] - prop["fird"] = (1-x)*phi1["fird"] + x*phi2["fird"] + Dphi["fird"] - prop["firdd"] = (1-x)*phi1["firdd"] + x*phi2["firdd"] + Dphi["firdd"] - prop["firdt"] = (1-x)*phi1["firdt"] + x*phi2["firdt"] + Dphi["firdt"] - prop["firx"] = -phi1["fir"] + phi2["fir"] + Dphi["firx"] + prop["fir"] = (1-x)*phi1.fi + x*phi2.fi + Dphi["fir"] + prop["firt"] = (1-x)*phi1.fit + x*phi2.fit + Dphi["firt"] + prop["firtt"] = (1-x)*phi1.fitt + x*phi2.fitt + Dphi["firtt"] + prop["fird"] = (1-x)*phi1.fid + x*phi2.fid + Dphi["fird"] + prop["firdd"] = (1-x)*phi1.fidd + x*phi2.fidd + Dphi["firdd"] + prop["firdt"] = (1-x)*phi1.fidt + x*phi2.fidt + Dphi["firdt"] + prop["firx"] = -phi1.fi + phi2.fi + Dphi["firx"] prop["F"] = prop["firx"] - delta/rhon*drhonx*prop["fird"] + \ tau/Tn*dTnx*prop["firt"] return prop diff --git a/iapws/humidAir.py b/iapws/humidAir.py index caabfc0..cc5fa67 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -903,29 +903,27 @@ def _fav(self, T: float, rho: float, A: float) -> Dict[str, float]: prop = {} # Eq T11 - prop["fir"] = (1-A)*fv["fir"] + A*fa["fir"] + fmix["fir"] + prop["fir"] = (1-A)*fv.fi + A*fa.fi + fmix["fir"] # Eq T12 - prop["fira"] = -fv["fir"]-rhov*fv["fird"]+fa["fir"] + \ - rhoa*fa["fird"]+fmix["fira"] + prop["fira"] = -fv.fi-rhov*fv.fid+fa.fi + rhoa*fa.fid+fmix["fira"] # Eq T13 - prop["firt"] = (1-A)*fv["firt"]+A*fa["firt"]+fmix["firt"] + prop["firt"] = (1-A)*fv.fit+A*fa.fit+fmix["firt"] # Eq T14 - prop["fird"] = (1-A)**2*fv["fird"]+A**2*fa["fird"]+fmix["fird"] + prop["fird"] = (1-A)**2*fv.fid+A**2*fa.fid+fmix["fird"] # Eq T15 - prop["firaa"] = rho*(2*fv["fird"]+rhov*fv["firdd"] - + 2*fa["fird"]+rhoa*fa["firdd"])+fmix["firaa"] + prop["firaa"] = rho*(2*fv.fid+rhov*fv.fidd + + 2*fa.fid+rhoa*fa.fidd)+fmix["firaa"] # Eq T16 - prop["firat"] = -fv["firt"]-rhov*fv["firdt"]+fa["firt"] + \ - rhoa*fa["firdt"]+fmix["firat"] + prop["firat"] = -fv.fit-rhov*fv.fidt+fa.fit + rhoa*fa.fidt+fmix["firat"] # Eq T17 - prop["firad"] = -(1-A)*(2*fv["fird"]+rhov*fv["firdd"]) + \ - A*(2*fa["fird"]+rhoa*fa["firdd"])+fmix["firad"] + prop["firad"] = -(1-A)*(2*fv.fid+rhov*fv.fidd) + \ + A*(2*fa.fid+rhoa*fa.fidd)+fmix["firad"] # Eq T18 - prop["firtt"] = (1-A)*fv["firtt"]+A*fa["firtt"]+fmix["firtt"] + prop["firtt"] = (1-A)*fv.fitt+A*fa.fitt+fmix["firtt"] # Eq T19 - prop["firdt"] = (1-A)**2*fv["firdt"]+A**2*fa["firdt"]+fmix["firdt"] + prop["firdt"] = (1-A)**2*fv.fidt+A**2*fa.fidt+fmix["firdt"] # Eq T20 - prop["firdd"] = (1-A)**3*fv["firdd"]+A**3*fa["firdd"]+fmix["firdd"] + prop["firdd"] = (1-A)**3*fv.fidd+A**3*fa.fidd+fmix["firdd"] return prop def _fmix(self, T: float, rho: float, A: float) -> Dict[str, float]: diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 92b70b6..c22022c 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -22,7 +22,7 @@ from ._iapws import _global_M, Tc, Pc, rhoc, Tc_D2O, Pc_D2O, rhoc_D2O from ._iapws import _Viscosity, _ThCond, _Dielectric, _Refractive, _Tension from ._iapws import _D2O_Viscosity, _D2O_ThCond, _D2O_Tension -from ._utils import _fase, getphase, deriv_H +from ._utils import _fase, getphase, deriv_H, HelmholtzDerivatives def _phir(tau: float, delta: float, coef: Dict[str, List[float]]) -> float: @@ -619,7 +619,7 @@ def rho_func(rho: float) -> float: elif self._mode == "Th": tau = Tc/T ideal = self._phi0(tau, 1) - fiot = ideal["fiot"] + fiot = ideal.fit def rho_func(rho: float) -> float: delta = rho/rhoc @@ -669,11 +669,9 @@ def rho_func(rho: float) -> float: delta = rho/rhoc ideal = self._phi0(tau, delta) - fio = ideal["fio"] - fiot = ideal["fiot"] fir = _phir(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) - so = self.R*(tau*(fiot+firt)-fio-fir) + so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) return so-s if T >= self.Tc: @@ -687,15 +685,13 @@ def rho_func(rho: float) -> float: idealL = self._phi0(tau, deltaL) idealG = self._phi0(tau, deltaG) - fioL = idealL["fio"] - fioG = idealG["fio"] - fiot = idealL["fiot"] + firL = _phir(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) - sl = self.R*(tau*(fiot+firtL)-fioL-firL) + sl = self.R*(tau*(idealL.fit+firtL)-idealL.fi-firL) firG = _phir(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) - sv = self.R*(tau*(fiot+firtG)-fioG-firG) + sv = self.R*(tau*(idealL.fit+firtG)-idealG.fi-firG) if sl <= s <= sv: rhol, rhov, Ps = self._saturation(T) @@ -716,7 +712,6 @@ def rho_func(rho: float) -> float: elif self._mode == "Tu": tau = Tc/T ideal = self._phi0(tau, 1) - fiot = ideal["fiot"] def rho_func(rho: float) -> float: delta = rho/rhoc @@ -724,7 +719,7 @@ def rho_func(rho: float) -> float: fird = _phird(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) Po = (1+delta*fird)*self.R*T*rho - ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) + ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) return ho-Po/rho-u @@ -743,8 +738,8 @@ def rho_func(rho: float) -> float: firtG = _phirt(tau, deltaG, self._constants) PoL = (1+deltaL*firdL)*self.R*T*rhol PoG = (1+deltaG*firdG)*self.R*T*rhov - hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) - hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) + hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) + hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) uv = hoG-PoG/rhov ul = hoL-PoL/rhol @@ -825,11 +820,10 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: tau = Tc/T ideal = self._phi0(tau, delta) - fiot = ideal["fiot"] fird = _phird(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) Po = (1+delta*fird)*self.R*T*rho - ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) + ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) return Po-P*1000, ho-h rho, T = tuple(map(float, fsolve(f2, [rhoo, To]))) @@ -845,16 +839,15 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ deltaG = rhog/self.rhoc ideal = self._phi0(tau, deltaL) - fiot = ideal["fiot"] firL = _phir(tau, deltaL, self._constants) firdL = _phird(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) - hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) + hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) firG = _phir(tau, deltaG, self._constants) firdG = _phird(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) - hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) + hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) @@ -896,13 +889,11 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: tau = Tc/T ideal = self._phi0(tau, delta) - fio = ideal["fio"] - fiot = ideal["fiot"] fird = _phird(tau, delta, self._constants) fir = _phir(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) Po = (1+delta*fird)*self.R*T*rho - so = self.R*(tau*(fiot+firt)-fio-fir) + so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) return Po-P*1000, so-s rho, T = tuple(map(float, fsolve(f2, [rhoo, To]))) @@ -930,11 +921,10 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: tau = Tc/T ideal = self._phi0(tau, delta) - fiot = ideal["fiot"] fird = _phird(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) Po = (1+delta*fird)*self.R*T*rho - ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) + ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) return ho-Po/rho-u, Po-P*1000 sol = fsolve(f2, [rhoo, To], full_output=True) @@ -951,16 +941,15 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ deltaG = rhog/self.rhoc ideal = self._phi0(tau, deltaL) - fiot = ideal["fiot"] firL = _phir(tau, deltaL, self._constants) firdL = _phird(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) - hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) + hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) firG = _phir(tau, deltaG, self._constants) firdG = _phird(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) - hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) + hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) @@ -999,10 +988,9 @@ def t_func(T: float) -> float: tau = Tc/T ideal = self._phi0(tau, delta) - fiot = ideal["fiot"] fird = _phird(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) - ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) + ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) return ho-h T = float(fsolve(t_func, To)[0]) @@ -1016,15 +1004,14 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: deltaG = rhog/self.rhoc ideal = self._phi0(tau, deltaL) - fiot = ideal["fiot"] firL = _phir(tau, deltaL, self._constants) firdL = _phird(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) - hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) + hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) firG = _phir(tau, deltaG, self._constants) firdG = _phird(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) - hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) + hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) @@ -1061,11 +1048,9 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: def t_func(T: float) -> float: tau = Tc/T ideal = self._phi0(tau, delta) - fio = ideal["fio"] - fiot = ideal["fiot"] fir = _phir(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) - so = self.R*(tau*(fiot+firt)-fio-fir) + so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) return so-s T = float(fsolve(t_func, To)[0]) @@ -1080,19 +1065,16 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: deltaG = rhog/self.rhoc idealL = self._phi0(tau, deltaL) - fioL = idealL["fio"] - fiot = idealL["fiot"] idealG = self._phi0(tau, deltaG) - fioG = idealG["fio"] firL = _phir(tau, deltaL, self._constants) firdL = _phird(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) - soL = self.R*(tau*(fiot+firtL)-fioL-firL) + soL = self.R*(tau*(idealL.fit+firtL)-idealL.fi-firL) firG = _phir(tau, deltaG, self._constants) firdG = _phird(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) - soG = self.R*(tau*(fiot+firtG)-fioG-firG) + soG = self.R*(tau*(idealL.fit+firtG)-idealG.fi-firG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) @@ -1130,11 +1112,10 @@ def t_func(T: float) -> float: tau = Tc/T ideal = self._phi0(tau, delta) - fiot = ideal["fiot"] fird = _phird(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) Po = (1+delta*fird)*self.R*T*rho - ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) + ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) return ho-Po/rho-u T = float(fsolve(t_func, To)[0]) @@ -1148,15 +1129,14 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: deltaG = rhog/self.rhoc ideal = self._phi0(tau, deltaL) - fiot = ideal["fiot"] firL = _phir(tau, deltaL, self._constants) firdL = _phird(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) - hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) + hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) firG = _phir(tau, deltaG, self._constants) firdG = _phird(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) - hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) + hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) @@ -1197,13 +1177,11 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: tau = Tc/T ideal = self._phi0(tau, delta) - fio = ideal["fio"] - fiot = ideal["fiot"] fird = _phird(tau, delta, self._constants) fir = _phir(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) - ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) - so = self.R*(tau*(fiot+firt)-fio-fir) + ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) + so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) return ho-h, so-s rho, T = tuple(map(float, fsolve(f2, [rhoo, To]))) @@ -1219,21 +1197,18 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ deltaG = rhog/self.rhoc idealL = self._phi0(tau, deltaL) - fiot = idealL["fiot"] - fioL = idealL["fio"] idealG = self._phi0(tau, deltaG) - fioG = idealG["fio"] firL = _phir(tau, deltaL, self._constants) firdL = _phird(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) - hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) - soL = self.R*(tau*(fiot+firtL)-fioL-firL) + hoL = self.R*T*(1+tau*(idealL.fit+firtL)+deltaL*firdL) + soL = self.R*(tau*(idealL.fit+firtL)-idealL.fi-firL) firG = _phir(tau, deltaG, self._constants) firdG = _phird(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) - hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) - soG = self.R*(tau*(fiot+firtG)-fioG-firG) + hoG = self.R*T*(1+tau*(idealL.fit+firtG)+deltaG*firdG) + soG = self.R*(tau*(idealL.fit+firtG)-idealG.fi-firG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) @@ -1267,11 +1242,10 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: tau = Tc/T ideal = self._phi0(tau, delta) - fiot = ideal["fiot"] fird = _phird(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) Po = (1+delta*fird)*self.R*T*rho - ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) + ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) return ho-Po/rho-u, ho-h @@ -1289,16 +1263,15 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ deltaG = rhog/self.rhoc ideal = self._phi0(tau, deltaL) - fiot = ideal["fiot"] firL = _phir(tau, deltaL, self._constants) firdL = _phird(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) - hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) + hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) firG = _phir(tau, deltaG, self._constants) firdG = _phird(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) - hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) + hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) @@ -1337,13 +1310,11 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: tau = Tc/T ideal = self._phi0(tau, delta) - fio = ideal["fio"] - fiot = ideal["fiot"] fird = _phird(tau, delta, self._constants) fir = _phir(tau, delta, self._constants) firt = _phirt(tau, delta, self._constants) - ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) - so = self.R*(tau*(fiot+firt)-fio-fir) + ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) + so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) Po = (1+delta*fird)*self.R*T*rho return ho-Po/rho-u, so-s @@ -1361,21 +1332,18 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ deltaG = rhog/self.rhoc idealL = self._phi0(tau, deltaL) - fiot = idealL["fiot"] - fioL = idealL["fio"] idealG = self._phi0(tau, deltaG) - fioG = idealG["fio"] firL = _phir(tau, deltaL, self._constants) firdL = _phird(tau, deltaL, self._constants) firtL = _phirt(tau, deltaL, self._constants) - hoL = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) - soL = self.R*(tau*(fiot+firtL)-fioL-firL) + hoL = self.R*T*(1+tau*(idealL.fit+firtL)+deltaL*firdL) + soL = self.R*(tau*(idealL.fit+firtL)-idealL.fi-firL) firG = _phir(tau, deltaG, self._constants) firdG = _phird(tau, deltaG, self._constants) firtG = _phirt(tau, deltaG, self._constants) - hoG = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) - soG = self.R*(tau*(fiot+firtG)-fioG-firG) + hoG = self.R*T*(1+tau*(idealL.fit+firtG)+deltaG*firdG) + soG = self.R*(tau*(idealL.fit+firtG)-idealG.fi-firG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) @@ -1742,32 +1710,23 @@ def _Helmholtz(self, rho: float, T: float) -> Dict[str, float]: delta = rho/rhoc tau = Tc/T ideal = self._phi0(tau, delta) - fio = ideal["fio"] - fiot = ideal["fiot"] - fiott = ideal["fiott"] res = self._phir(tau, delta) - fir = res["fir"] - firt = res["firt"] - firtt = res["firtt"] - fird = res["fird"] - firdd = res["firdd"] - firdt = res["firdt"] propiedades = {} - propiedades["fir"] = fir - propiedades["fird"] = fird - propiedades["firdd"] = firdd + propiedades["fir"] = res.fi + propiedades["fird"] = res.fid + propiedades["firdd"] = res.fidd propiedades["delta"] = delta propiedades["rho"] = rho - propiedades["P"] = (1+delta*fird)*self.R*T*rho - propiedades["h"] = self.R*T*(1+tau*(fiot+firt)+delta*fird) - propiedades["s"] = self.R*(tau*(fiot+firt)-fio-fir) - propiedades["cv"] = -self.R*tau**2*(fiott+firtt) - propiedades["alfap"] = (1-delta*tau*firdt/(1+delta*fird))/T + propiedades["P"] = (1+delta*res.fid)*self.R*T*rho + propiedades["h"] = self.R*T*(1+tau*(ideal.fit+res.fit)+delta*res.fid) + propiedades["s"] = self.R*(tau*(ideal.fit+res.fit)-ideal.fi-res.fi) + propiedades["cv"] = -self.R*tau**2*(ideal.fitt+res.fitt) + propiedades["alfap"] = (1-delta*tau*res.fidt/(1+delta*res.fid))/T propiedades["betap"] = rho*( - 1+(delta*fird+delta**2*firdd)/(1+delta*fird)) + 1+(delta*res.fid+delta**2*res.fidd)/(1+delta*res.fid)) return propiedades def _prop0(self, rho: float, T: float) -> _fase: @@ -1777,20 +1736,17 @@ def _prop0(self, rho: float, T: float) -> _fase: delta = rho/rhoc tau = Tc/T ideal = self._phi0(tau, delta) - fio = ideal["fio"] - fiot = ideal["fiot"] - fiott = ideal["fiott"] propiedades = _fase() - propiedades.h = self.R*T*(1+tau*fiot) - propiedades.s = self.R*(tau*fiot-fio) - propiedades.cv = -self.R*tau**2*fiott - propiedades.cp = self.R*(-tau**2*fiott+1) + propiedades.h = self.R*T*(1+tau*ideal.fit) + propiedades.s = self.R*(tau*ideal.fit-ideal.fi) + propiedades.cv = -self.R*tau**2*ideal.fitt + propiedades.cp = self.R*(-tau**2*ideal.fitt+1) propiedades.alfap = 1.0/T propiedades.betap = rho return propiedades - def _phi0(self, tau: float, delta: float) -> Dict[str, float]: + def _phi0(self, tau: float, delta: float) -> HelmholtzDerivatives: """Ideal gas Helmholtz free energy and derivatives Parameters @@ -1864,16 +1820,9 @@ def _phi0(self, tau: float, delta: float) -> Dict[str, float]: fiot += n*g/(C*exp(-g*tau)+1) fiott += C*n*g**2*exp(-g*tau)/(C*exp(-g*tau)+1)**2 - prop = {} - prop["fio"] = fio - prop["fiot"] = fiot - prop["fiott"] = fiott - prop["fiod"] = fiod - prop["fiodd"] = fiodd - prop["fiodt"] = fiodt - return prop + return HelmholtzDerivatives(fio, fiot, fiod, fiott, fiodd, fiodt) - def _phir(self, tau: float, delta: float) -> Dict[str, float]: + def _phir(self, tau: float, delta: float) -> HelmholtzDerivatives: """Residual contribution to the free Helmholtz energy Parameters @@ -1885,8 +1834,8 @@ def _phir(self, tau: float, delta: float) -> Dict[str, float]: Returns ------- - prop : dict - Dictionary with residual adimensional helmholtz energy and deriv: + HelmholtzDerivatives class, with residual adimensional helmholtz + energy and deriv: * fir * firt: ∂fir/∂τ|δ,x * fird: ∂fir/∂δ|τ,x @@ -2009,14 +1958,7 @@ def _phir(self, tau: float, delta: float) -> Dict[str, float]: firdt += n*(Delta**b*(Ft+delta*Fdt)+delta*DeltaBd*Ft + DeltaBt*(F+delta*Fd)+DeltaBdt*delta*F) - prop = {} - prop["fir"] = fir - prop["firt"] = firt - prop["firtt"] = firtt - prop["fird"] = fird - prop["firdd"] = firdd - prop["firdt"] = firdt - return prop + return HelmholtzDerivatives(fir, firt, fird, firtt, firdd, firdt) def _virial(self, T: float) -> Dict[str, float]: """Virial coefficient @@ -2106,7 +2048,7 @@ def _virial(self, T: float) -> Dict[str, float]: prop["C"] = C return prop - def _derivDimensional(self, rho: float, T: float) -> Dict[str, float]: + def _derivDimensional(self, rho: float, T: float) -> HelmholtzDerivatives: """Calcule the dimensional form or Helmholtz free energy derivatives Parameters @@ -2136,14 +2078,7 @@ def _derivDimensional(self, rho: float, T: float) -> Dict[str, float]: http://www.iapws.org/relguide/SeaAir.html """ if not rho: - prop = {} - prop["fir"] = 0.0 - prop["firt"] = 0.0 - prop["fird"] = 0.0 - prop["firtt"] = 0.0 - prop["firdt"] = 0.0 - prop["firdd"] = 0.0 - return prop + return HelmholtzDerivatives(0.0, 0.0, 0.0, 0.0, 0.0, 0.0) rhoc = self._constants.get("rhoref", [self.rhoc])[0] Tc = self._constants.get("Tref", [self.Tc])[0] @@ -2151,30 +2086,18 @@ def _derivDimensional(self, rho: float, T: float) -> Dict[str, float]: tau = Tc/T ideal = self._phi0(tau, delta) - fio = ideal["fio"] - fiot = ideal["fiot"] - fiott = ideal["fiott"] - fiod = ideal["fiod"] - fiodd = ideal["fiodd"] res = self._phir(tau, delta) - fir = res["fir"] - firt = res["firt"] - firtt = res["firtt"] - fird = res["fird"] - firdd = res["firdd"] - firdt = res["firdt"] R = self.R - prop = {} - prop["fir"] = R*T*(fio+fir) - prop["firt"] = R*(fio+fir-(fiot+firt)*tau) - prop["fird"] = R*T/rhoc*(fiod+fird) - prop["firtt"] = R*tau**2/T*(fiott+firtt) - prop["firdt"] = R/rhoc*(fiod+fird-firdt*tau) - prop["firdd"] = R*T/rhoc**2*(fiodd+firdd) - return prop + fir = R*T*(ideal.fi+res.fi) + firt = R*(ideal.fi+res.fi-(ideal.fit+res.fit)*tau) + fird = R*T/rhoc*(ideal.fid+res.fid) + firtt = R*tau**2/T*(ideal.fitt+res.fitt) + firdt = R/rhoc*(ideal.fid+res.fid-res.fidt*tau) + firdd = R*T/rhoc**2*(ideal.fidd+res.fidd) + return HelmholtzDerivatives(fir, firt, fird, firtt, firdd, firdt) def _surface(self, T: float) -> float: """Generic equation for the surface tension @@ -2553,16 +2476,16 @@ class IAPWS95(MEoS): def __init__(self, **kwargs): super().__init__(**kwargs) - def _phi0(self, tau: float, delta: float) -> Dict[str, float]: + def _phi0(self, tau: float, delta: float) -> HelmholtzDerivatives: """Low temperature extension of the IAPWS-95""" prop = MEoS._phi0(self, tau, delta) T = self.Tc/tau if 50 <= T < 130: fex, fext, fextt = self._phiex(T) - prop["fio"] += fex - prop["fiot"] += fext - prop["fiott"] += fextt + prop.fi += fex + prop.fit += fext + prop.fitt += fextt return prop def _phiex(self, T: float) -> Tuple[float, float, float]: diff --git a/test.py b/test.py index 68f843e..43fe229 100755 --- a/test.py +++ b/test.py @@ -52,20 +52,20 @@ def test_Helmholtz(self) -> None: tau = fluid.Tc/T ideal = fluid._phi0(tau, delta) - self.assertEqual(round(ideal["fio"], 8), 2.04797733) - self.assertEqual(round(ideal["fiod"], 9), 0.384236747) - self.assertEqual(round(ideal["fiodd"], 9), -0.147637878) - self.assertEqual(round(ideal["fiot"], 8), 9.04611106) - self.assertEqual(round(ideal["fiott"], 8), -1.93249185) - self.assertEqual(round(ideal["fiodt"], 8), 0.0) + self.assertEqual(round(ideal.fi, 8), 2.04797733) + self.assertEqual(round(ideal.fid, 9), 0.384236747) + self.assertEqual(round(ideal.fidd, 9), -0.147637878) + self.assertEqual(round(ideal.fit, 8), 9.04611106) + self.assertEqual(round(ideal.fitt, 8), -1.93249185) + self.assertEqual(round(ideal.fidt, 8), 0.0) res = fluid._phir(tau, delta) - self.assertEqual(round(res["fir"], 8), -3.42693206) - self.assertEqual(round(res["fird"], 9), -0.364366650) - self.assertEqual(round(res["firdd"], 9), 0.856063701) - self.assertEqual(round(res["firt"], 8), -5.81403435) - self.assertEqual(round(res["firtt"], 8), -2.23440737) - self.assertEqual(round(res["firdt"], 8), -1.12176915) + self.assertEqual(round(res.fi, 8), -3.42693206) + self.assertEqual(round(res.fid, 9), -0.364366650) + self.assertEqual(round(res.fidd, 9), 0.856063701) + self.assertEqual(round(res.fit, 8), -5.81403435) + self.assertEqual(round(res.fitt, 8), -2.23440737) + self.assertEqual(round(res.fidt, 8), -1.12176915) # Revised release of 2018 # Virial coefficient in Table 3 @@ -1253,19 +1253,19 @@ def test_D2O(self) -> None: delta = 46.26*fluid.M/fluid.rhoc tau = fluid.Tc/500 ideal = fluid._phi0(tau, delta) - self.assertEqual(round(ideal["fio"], 8), 1.96352717) - self.assertEqual(round(ideal["fiod"], 9), 0.384253134) - self.assertEqual(round(ideal["fiodd"], 9), -0.147650471) - self.assertEqual(round(ideal["fiot"], 8), 9.39259413) - self.assertEqual(round(ideal["fiott"], 8), -2.09517144) - self.assertEqual(round(ideal["fiodt"], 8), 0) + self.assertEqual(round(ideal.fi, 8), 1.96352717) + self.assertEqual(round(ideal.fid, 9), 0.384253134) + self.assertEqual(round(ideal.fidd, 9), -0.147650471) + self.assertEqual(round(ideal.fit, 8), 9.39259413) + self.assertEqual(round(ideal.fitt, 8), -2.09517144) + self.assertEqual(round(ideal.fidt, 8), 0) res = fluid._phir(tau, delta) - self.assertEqual(round(res["fir"], 8), -3.42291092) - self.assertEqual(round(res["fird"], 9), -0.367562780) - self.assertEqual(round(res["firdd"], 9), 0.835183806) - self.assertEqual(round(res["firt"], 8), -5.89707436) - self.assertEqual(round(res["firtt"], 8), -2.45187285) - self.assertEqual(round(res["firdt"], 8), -1.13178440) + self.assertEqual(round(res.fi, 8), -3.42291092) + self.assertEqual(round(res.fid, 9), -0.367562780) + self.assertEqual(round(res.fidd, 9), 0.835183806) + self.assertEqual(round(res.fit, 8), -5.89707436) + self.assertEqual(round(res.fitt, 8), -2.45187285) + self.assertEqual(round(res.fidt, 8), -1.13178440) # Table 7, Pag 12, Single phase region st = D2O(T=300, rhom=55.126) @@ -2441,20 +2441,20 @@ def test_HumidAir(self) -> None: T = 200 rho = 1.63479657e-5 psy = HumidAir() - fa = psy._fav(T, rho, A) - self.assertEqual(round(fa["fir"], 6), -0.682093392e3) - self.assertEqual(round(fa["fira"], 6), -0.572680404e3) - self.assertEqual(round(fa["firt"], 8), -0.405317966e1) - self.assertEqual(round(fa["fird"], 2), 0.374173101e7) - self.assertEqual(round(fa["firaa"], 6), 0.920967684e3) - self.assertEqual(round(fa["firat"], 8), 0.915653743e1) - self.assertEqual(round(fa["firad"], 2), -0.213442099e7) - self.assertEqual(round(fa["firtt"], 11), -0.394011921e-2) - self.assertEqual(round(fa["firdt"], 4), 0.187087034e5) - self.assertEqual(round(fa["firdd"]*1e-6, 3), -0.228880603e6) - colig = psy._coligative(rho, A, fa) + fav = psy._fav(T, rho, A) + self.assertEqual(round(fav["fir"], 6), -0.682093392e3) + self.assertEqual(round(fav["fira"], 6), -0.572680404e3) + self.assertEqual(round(fav["firt"], 8), -0.405317966e1) + self.assertEqual(round(fav["fird"], 2), 0.374173101e7) + self.assertEqual(round(fav["firaa"], 6), 0.920967684e3) + self.assertEqual(round(fav["firat"], 8), 0.915653743e1) + self.assertEqual(round(fav["firad"], 2), -0.213442099e7) + self.assertEqual(round(fav["firtt"], 11), -0.394011921e-2) + self.assertEqual(round(fav["firdt"], 4), 0.187087034e5) + self.assertEqual(round(fav["firdd"]*1e-6, 3), -0.228880603e6) + colig = psy._coligative(rho, A, fav) self.assertEqual(round(colig["muw"], 6), -0.109950917e3) - prop = psy._prop(T, rho, fa) + prop = psy._prop(T, rho, fav) self.assertEqual(round(prop["P"], 15), 0.999999998e-6) self.assertEqual(round(prop["h"], 6), 0.189712231e3) self.assertEqual(round(prop["g"], 6), -0.620923701e3) @@ -2466,20 +2466,20 @@ def test_HumidAir(self) -> None: T = 300 rho = 1.14614216 psy = HumidAir() - fa = psy._fav(T, rho, A) - self.assertEqual(round(fa["fir"], 7), -0.927718178e2) - self.assertEqual(round(fa["fira"], 9), -0.263453864) - self.assertEqual(round(fa["firt"], 9), -0.296711481) - self.assertEqual(round(fa["fird"], 7), 0.761242496e2) - self.assertEqual(round(fa["firaa"], 5), 0.624886233e4) - self.assertEqual(round(fa["firat"], 8), 0.822733446e1) - self.assertEqual(round(fa["firad"], 7), -0.450004399e2) - self.assertEqual(round(fa["firtt"], 11), -0.244742952e-2) - self.assertEqual(round(fa["firdt"], 9), 0.254456302) - self.assertEqual(round(fa["firdd"], 7), -0.664465525e2) - colig = psy._coligative(rho, A, fa) + fav = psy._fav(T, rho, A) + self.assertEqual(round(fav["fir"], 7), -0.927718178e2) + self.assertEqual(round(fav["fira"], 9), -0.263453864) + self.assertEqual(round(fav["firt"], 9), -0.296711481) + self.assertEqual(round(fav["fird"], 7), 0.761242496e2) + self.assertEqual(round(fav["firaa"], 5), 0.624886233e4) + self.assertEqual(round(fav["firat"], 8), 0.822733446e1) + self.assertEqual(round(fav["firad"], 7), -0.450004399e2) + self.assertEqual(round(fav["firtt"], 11), -0.244742952e-2) + self.assertEqual(round(fav["firdt"], 9), 0.254456302) + self.assertEqual(round(fav["firdd"], 7), -0.664465525e2) + colig = psy._coligative(rho, A, fav) self.assertEqual(round(colig["muw"], 8), -0.526505193e1) - prop = psy._prop(T, rho, fa) + prop = psy._prop(T, rho, fav) self.assertEqual(round(prop["P"], 9), 0.1) self.assertEqual(round(prop["h"], 7), 0.834908383e2) self.assertEqual(round(prop["g"], 8), -0.552260595e1) @@ -2491,20 +2491,20 @@ def test_HumidAir(self) -> None: T = 400 rho = 0.793354063e1 psy = HumidAir() - fa = psy._fav(T, rho, A) - self.assertEqual(round(fa["fir"], 7), 0.240345570e2) - self.assertEqual(round(fa["fira"], 6), 0.311096733e3) - self.assertEqual(round(fa["firt"], 8), -0.106891931e1) - self.assertEqual(round(fa["fird"], 7), 0.158878781e2) - self.assertEqual(round(fa["firaa"], 5), 0.113786423e4) - self.assertEqual(round(fa["firat"], 8), 0.702631471e1) - self.assertEqual(round(fa["firad"], 8), -0.727972651e1) - self.assertEqual(round(fa["firtt"], 11), -0.222449294e-2) - self.assertEqual(round(fa["firdt"], 10), 0.414350772e-1) - self.assertEqual(round(fa["firdd"], 8), -0.201886184e1) - colig = psy._coligative(rho, A, fa) + fav = psy._fav(T, rho, A) + self.assertEqual(round(fav["fir"], 7), 0.240345570e2) + self.assertEqual(round(fav["fira"], 6), 0.311096733e3) + self.assertEqual(round(fav["firt"], 8), -0.106891931e1) + self.assertEqual(round(fav["fird"], 7), 0.158878781e2) + self.assertEqual(round(fav["firaa"], 5), 0.113786423e4) + self.assertEqual(round(fav["firat"], 8), 0.702631471e1) + self.assertEqual(round(fav["firad"], 8), -0.727972651e1) + self.assertEqual(round(fav["firtt"], 11), -0.222449294e-2) + self.assertEqual(round(fav["firdt"], 10), 0.414350772e-1) + self.assertEqual(round(fav["firdd"], 8), -0.201886184e1) + colig = psy._coligative(rho, A, fav) self.assertEqual(round(colig["muw"], 6), -0.106748981e3) - prop = psy._prop(T, rho, fa) + prop = psy._prop(T, rho, fav) self.assertEqual(round(prop["P"], 8), 1) self.assertEqual(round(prop["h"], 6), 0.577649408e3) self.assertEqual(round(prop["g"], 6), 0.150081684e3) @@ -2520,25 +2520,25 @@ def test_HumidAir(self) -> None: rhov = (1-A)*rho air = Air() fa = air._derivDimensional(0, T) - self.assertEqual(round(fa["fir"], 6), 0) + self.assertEqual(round(fa.fi, 6), 0) fa = air._derivDimensional(rhoa, T) self.assertEqual(round(rhoa, 13), 1.45864351e-5) - self.assertEqual(round(fa["fir"], 6), -0.740041144e3) - self.assertEqual(round(fa["firt"], 8), -0.304774177e1) - self.assertEqual(round(fa["fird"], 2), 0.393583654e7) - self.assertEqual(round(fa["firtt"], 11), -0.357677878e-2) - self.assertEqual(round(fa["firdt"], 4), 0.196791837e5) - self.assertEqual(round(fa["firdd"]*1e-6, 3), -0.269828549e6) + self.assertEqual(round(fa.fi, 6), -0.740041144e3) + self.assertEqual(round(fa.fit, 8), -0.304774177e1) + self.assertEqual(round(fa.fid, 2), 0.393583654e7) + self.assertEqual(round(fa.fitt, 11), -0.357677878e-2) + self.assertEqual(round(fa.fidt, 4), 0.196791837e5) + self.assertEqual(round(fa.fidd*1e-6, 3), -0.269828549e6) water = IAPWS95() fv = water._derivDimensional(rhov, T) self.assertEqual(round(rhov, 14), 1.76153059e-6) - self.assertEqual(round(fv["fir"], 6), -0.202254351e3) - self.assertEqual(round(fv["firt"], 7), -0.123787544e2) - self.assertEqual(round(fv["fird"], 1), 0.523995674e8) - self.assertEqual(round(fv["firtt"], 11), -0.694877601e-2) - self.assertEqual(round(fv["firdt"], 3), 0.262001885e6) - self.assertEqual(round(fv["firdd"]*1e-6, 1), -0.297466671e8) + self.assertEqual(round(fv.fi, 6), -0.202254351e3) + self.assertEqual(round(fv.fit, 7), -0.123787544e2) + self.assertEqual(round(fv.fid, 1), 0.523995674e8) + self.assertEqual(round(fv.fitt, 11), -0.694877601e-2) + self.assertEqual(round(fv.fidt, 3), 0.262001885e6) + self.assertEqual(round(fv.fidd*1e-6, 1), -0.297466671e8) A = 0.977605798 T = 300 @@ -2548,21 +2548,21 @@ def test_HumidAir(self) -> None: air = Air() fa = air._derivDimensional(rhoa, T) self.assertEqual(round(rhoa, 8), 1.12047522) - self.assertEqual(round(fa["fir"], 7), -0.916103453e2) - self.assertEqual(round(fa["firt"], 9), -0.108476220) - self.assertEqual(round(fa["fird"], 7), 0.768326795e2) - self.assertEqual(round(fa["firtt"], 11), -0.239319940e-2) - self.assertEqual(round(fa["firdt"], 9), 0.256683306) - self.assertEqual(round(fa["firdd"], 7), -0.685917373e2) + self.assertEqual(round(fa.fi, 7), -0.916103453e2) + self.assertEqual(round(fa.fit, 9), -0.108476220) + self.assertEqual(round(fa.fid, 7), 0.768326795e2) + self.assertEqual(round(fa.fitt, 11), -0.239319940e-2) + self.assertEqual(round(fa.fidt, 9), 0.256683306) + self.assertEqual(round(fa.fidd, 7), -0.685917373e2) water = IAPWS95() fv = water._derivDimensional(rhov, T) self.assertEqual(round(rhov, 10), 0.256669391e-1) - self.assertEqual(round(fv["fir"], 6), -0.143157426e3) - self.assertEqual(round(fv["firt"], 8), -0.851598213e1) - self.assertEqual(round(fv["fird"], 5), 0.538480619e4) - self.assertEqual(round(fv["firtt"], 11), -0.480817011e-2) - self.assertEqual(round(fv["firdt"], 7), 0.181489502e2) - self.assertEqual(round(fv["firdd"], 3), -0.210184992e6) + self.assertEqual(round(fv.fi, 6), -0.143157426e3) + self.assertEqual(round(fv.fit, 8), -0.851598213e1) + self.assertEqual(round(fv.fid, 5), 0.538480619e4) + self.assertEqual(round(fv.fitt, 11), -0.480817011e-2) + self.assertEqual(round(fv.fidt, 7), 0.181489502e2) + self.assertEqual(round(fv.fidd, 3), -0.210184992e6) A = 0.825565291 T = 400 @@ -2572,21 +2572,21 @@ def test_HumidAir(self) -> None: air = Air() fa = air._derivDimensional(rhoa, T) self.assertEqual(round(rhoa, 8), 0.654965578e1) - self.assertEqual(round(fa["fir"], 7), 0.895561286e2) - self.assertEqual(round(fa["firt"], 9), 0.193271394) - self.assertEqual(round(fa["fird"], 7), 0.175560114e2) - self.assertEqual(round(fa["firtt"], 11), -0.181809877e-2) - self.assertEqual(round(fa["firdt"], 10), 0.442769673e-1) - self.assertEqual(round(fa["firdd"], 8), -0.267635928e1) + self.assertEqual(round(fa.fi, 7), 0.895561286e2) + self.assertEqual(round(fa.fit, 9), 0.193271394) + self.assertEqual(round(fa.fid, 7), 0.175560114e2) + self.assertEqual(round(fa.fitt, 11), -0.181809877e-2) + self.assertEqual(round(fa.fidt, 10), 0.442769673e-1) + self.assertEqual(round(fa.fidd, 8), -0.267635928e1) water = IAPWS95() fv = water._derivDimensional(rhov, T) self.assertEqual(round(rhov, 8), 0.138388485e1) - self.assertEqual(round(fv["fir"], 6), -0.285137534e3) - self.assertEqual(round(fv["firt"], 8), -0.705288048e1) - self.assertEqual(round(fv["fird"], 6), 0.129645039e3) - self.assertEqual(round(fv["firtt"], 11), -0.411710659e-2) - self.assertEqual(round(fv["firdt"], 9), 0.361784086) - self.assertEqual(round(fv["firdd"], 7), -0.965539462e2) + self.assertEqual(round(fv.fi, 6), -0.285137534e3) + self.assertEqual(round(fv.fit, 8), -0.705288048e1) + self.assertEqual(round(fv.fid, 6), 0.129645039e3) + self.assertEqual(round(fv.fitt, 11), -0.411710659e-2) + self.assertEqual(round(fv.fidt, 9), 0.361784086) + self.assertEqual(round(fv.fidd, 7), -0.965539462e2) # Table 15 A = 0.892247719 From 8acaab5dd6089a7f9f810f480b0872f6eb515989 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Thu, 18 Mar 2021 00:53:01 -0400 Subject: [PATCH 090/102] Convert IAPWS97 properties to a custom class. Better static typing and generally more readble code. For region 4, I returned 'nan' for the undefined properties, which migth cause a subtle API change. But now that there's a class, I can change back to Optional[float] easily enough if needed. --- iapws/iapws08.py | 14 +- iapws/iapws97.py | 456 +++++++++++++++++++++++------------------------ test.py | 148 +++++++-------- 3 files changed, 305 insertions(+), 313 deletions(-) diff --git a/iapws/iapws08.py b/iapws/iapws08.py index 6a299d9..9dc1088 100644 --- a/iapws/iapws08.py +++ b/iapws/iapws08.py @@ -476,10 +476,10 @@ def _Tb(P: float, S: float) -> float: """ def f(T: float) -> float: pw = _Region1(T, P) - gw = pw["h"]-T*pw["s"] + gw = pw.h-T*pw.s pv = _Region2(T, P) - gv = pv["h"]-T*pv["s"] + gv = pv.h-T*pv.s ps = SeaWater._saline(T, P, S) return -ps["g"]+S*ps["gs"]-gw+gv @@ -511,7 +511,7 @@ def _Tf(P: float, S: float) -> float: def f(T: float) -> float: T = float(T) pw = _Region1(T, P) - gw = pw["h"]-T*pw["s"] + gw = pw.h-T*pw.s gih = _Ice(T, P)["g"] @@ -547,10 +547,10 @@ def _Triple(S: float) -> Dict[str, float]: def f(parr: Tuple[float, float]) -> Tuple[float, float]: T, P = parr pw = _Region1(T, P) - gw = pw["h"]-T*pw["s"] + gw = pw.h-T*pw.s pv = _Region2(T, P) - gv = pv["h"]-T*pv["s"] + gv = pv.h-T*pv.s gih = _Ice(T, P)["g"] ps = SeaWater._saline(T, P, S) @@ -588,11 +588,11 @@ def _OsmoticPressure(T: float, P: float, S: float) -> float: Properties of Seawater, http://www.iapws.org/relguide/Advise5.html, Eq 15 """ pw = _Region1(T, P) - gw = pw["h"]-T*pw["s"] + gw = pw.h-T*pw.s def f(Posm: float) -> float: pw2 = _Region1(T, P+Posm) - gw2 = pw2["h"]-T*pw2["s"] + gw2 = pw2.h-T*pw2.s ps = SeaWater._saline(T, P+Posm, S) return -ps["g"]+S*ps["gs"]-gw+gw2 diff --git a/iapws/iapws97.py b/iapws/iapws97.py index aab395b..3c75565 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -401,8 +401,8 @@ def _PSat_h(h: float) -> float: 20.18090839 """ # Check input parameters - hmin_Ps3 = _Region1(623.15, Ps_623)["h"] - hmax_Ps3 = _Region2(623.15, Ps_623)["h"] + hmin_Ps3 = _Region1(623.15, Ps_623).h + hmax_Ps3 = _Region2(623.15, Ps_623).h if h < hmin_Ps3 or h > hmax_Ps3: raise NotImplementedError("Incoming out of bound") @@ -455,8 +455,8 @@ def _PSat_s(s: float) -> float: 16.68968482 """ # Check input parameters - smin_Ps3 = _Region1(623.15, Ps_623)["s"] - smax_Ps3 = _Region2(623.15, Ps_623)["s"] + smin_Ps3 = _Region1(623.15, Ps_623).s + smax_Ps3 = _Region2(623.15, Ps_623).s if s < smin_Ps3 or s > smax_Ps3: raise NotImplementedError("Incoming out of bound") @@ -703,8 +703,28 @@ def _h2c3b_s(s: float) -> float: return 2800*suma**4 +class IAPWS97Properties(object): + """The properties required to fill the IAPWS97 phase.""" + + def __init__(self, T: float, P: float, v: float, h: float, s: float, + cp: float, cv: float, w: float, alfav: float, kt: float, + region: int, x: float) -> None: + self.T = T + self.P = P + self.v = v + self.h = h + self.s = s + self.cp = cp + self.cv = cv + self.w = w + self.alfav = alfav + self.kt = kt + self.region = region + self.x = x + + # Region 1 -def _Region1(T: float, P: float) -> Dict[str, float]: +def _Region1(T: float, P: float) -> IAPWS97Properties: """Basic equation for region 1 Parameters @@ -736,23 +756,23 @@ def _Region1(T: float, P: float) -> Dict[str, float]: Examples -------- - >>> _Region1(300,3)["v"] + >>> _Region1(300,3).v 0.00100215168 - >>> _Region1(300,3)["h"] + >>> _Region1(300,3).h 115.331273 - >>> _Region1(300,3)["h"]-3000*_Region1(300,3)["v"] + >>> _Region1(300,3).h-3000*_Region1(300,3).v 112.324818 - >>> _Region1(300,80)["s"] + >>> _Region1(300,80).s 0.368563852 - >>> _Region1(300,80)["cp"] + >>> _Region1(300,80).cp 4.01008987 - >>> _Region1(300,80)["cv"] + >>> _Region1(300,80).cv 3.91736606 - >>> _Region1(500,3)["w"] + >>> _Region1(500,3).w 1240.71337 - >>> _Region1(500,3)["alfav"] + >>> _Region1(500,3).alfav 0.00164118128 - >>> _Region1(500,3)["kt"] + >>> _Region1(500,3).kt 0.00112892188 """ if P < 0: @@ -787,20 +807,15 @@ def _Region1(T: float, P: float) -> Dict[str, float]: R = _global_R - propiedades = {} - propiedades["T"] = T - propiedades["P"] = P - propiedades["v"] = Pr*gp*R*T/P/1000 - propiedades["h"] = Tr*gt*R*T - propiedades["s"] = R*(Tr*gt-g) - propiedades["cp"] = -R*Tr**2*gtt - propiedades["cv"] = R*(-Tr**2*gtt+(gp-Tr*gpt)**2/gpp) - propiedades["w"] = sqrt(R*T*1000*gp**2/((gp-Tr*gpt)**2/(Tr**2*gtt)-gpp)) - propiedades["alfav"] = (1-Tr*gpt/gp)/T - propiedades["kt"] = -Pr*gpp/gp/P - propiedades["region"] = 1 - propiedades["x"] = 0 - return propiedades + v = Pr*gp*R*T/P/1000 + h = Tr*gt*R*T + s = R*(Tr*gt-g) + cp = -R*Tr**2*gtt + cv = R*(-Tr**2*gtt+(gp-Tr*gpt)**2/gpp) + w = sqrt(R*T*1000*gp**2/((gp-Tr*gpt)**2/(Tr**2*gtt)-gpp)) + alfav = (1-Tr*gpt/gp)/T + kt = -Pr*gpp/gp/P + return IAPWS97Properties(T, P, v, h, s, cp, cv, w, alfav, kt, 1, 0.0) def _Backward1_T_Ph(P: float, h: float) -> float: @@ -946,7 +961,7 @@ def _Backward1_P_hs(h: float, s: float) -> float: # Region 2 -def _Region2(T: float, P: float) -> Dict[str, float]: +def _Region2(T: float, P: float) -> IAPWS97Properties: """Basic equation for region 2 Parameters @@ -978,23 +993,23 @@ def _Region2(T: float, P: float) -> Dict[str, float]: Examples -------- - >>> _Region2(700,30)["v"] + >>> _Region2(700,30).v 0.00542946619 - >>> _Region2(700,30)["h"] + >>> _Region2(700,30).h 2631.49474 - >>> _Region2(700,30)["h"]-30000*_Region2(700,30)["v"] + >>> _Region2(700,30).h-30000*_Region2(700,30).v 2468.61076 - >>> _Region2(700,0.0035)["s"] + >>> _Region2(700,0.0035).s 10.1749996 - >>> _Region2(700,0.0035)["cp"] + >>> _Region2(700,0.0035).cp 2.08141274 - >>> _Region2(700,0.0035)["cv"] + >>> _Region2(700,0.0035).cv 1.61978333 - >>> _Region2(300,0.0035)["w"] + >>> _Region2(300,0.0035).w 427.920172 - >>> _Region2(300,0.0035)["alfav"] + >>> _Region2(300,0.0035).alfav 0.00337578289 - >>> _Region2(300,0.0035)["kt"] + >>> _Region2(300,0.0035).kt 286.239651 """ if P < 0: @@ -1040,22 +1055,16 @@ def _Region2(T: float, P: float) -> Dict[str, float]: R = _global_R - propiedades = {} - propiedades["T"] = T - propiedades["P"] = P - propiedades["v"] = Pr*(gop+grp)*R*T/P/1000 - propiedades["h"] = Tr*(got+grt)*R*T - propiedades["s"] = R*(Tr*(got+grt)-(go+gr)) - propiedades["cp"] = -R*Tr**2*(gott+grtt) - propiedades["cv"] = R*(-Tr**2*(gott+grtt)-(1+Pr*grp-Tr*Pr*grpt)**2 - / (1-Pr**2*grpp)) - propiedades["w"] = (R*T*1000*(1+2*Pr*grp+Pr**2*grp**2)/(1-Pr**2*grpp+( + v = Pr*(gop+grp)*R*T/P/1000 + h = Tr*(got+grt)*R*T + s = R*(Tr*(got+grt)-(go+gr)) + cp = -R*Tr**2*(gott+grtt) + cv = R*(-Tr**2*(gott+grtt)-(1+Pr*grp-Tr*Pr*grpt)**2 / (1-Pr**2*grpp)) + w = (R*T*1000*(1+2*Pr*grp+Pr**2*grp**2)/(1-Pr**2*grpp+( 1+Pr*grp-Tr*Pr*grpt)**2/Tr**2/(gott+grtt)))**0.5 - propiedades["alfav"] = (1+Pr*grp-Tr*Pr*grpt)/(1+Pr*grp)/T - propiedades["kt"] = (1-Pr**2*grpp)/(1+Pr*grp)/P - propiedades["region"] = 2 - propiedades["x"] = 1 - return propiedades + alfav = (1+Pr*grp-Tr*Pr*grpt)/(1+Pr*grp)/T + kt = (1-Pr**2*grpp)/(1+Pr*grp)/P + return IAPWS97Properties(T, P, v, h, s, cp, cv, w, alfav, kt, 2, 1.0) def Region2_cp0(Tr: float, Pr: float) -> Tuple[float, float, float, float, float, float]: @@ -1181,8 +1190,8 @@ def _hab_s(s: float) -> float: >>> _hab_s(7) 3376.437884 """ - smin = _Region2(_TSat_P(4), 4)["s"] - smax = _Region2(1073.15, 4)["s"] + smin = _Region2(_TSat_P(4), 4).s + smax = _Region2(1073.15, 4).s if s < smin: h = 0.0 elif s > smax: @@ -1768,7 +1777,7 @@ def _Backward2_P_hs(h: float, s: float) -> float: # Region 3 -def _Region3(rho: float, T: float) -> Dict[str, float]: +def _Region3(rho: float, T: float) -> IAPWS97Properties: """Basic equation for region 3 Parameters @@ -1800,24 +1809,24 @@ def _Region3(rho: float, T: float) -> Dict[str, float]: Examples -------- - >>> _Region3(500,650)["P"] + >>> _Region3(500,650).P 25.5837018 - >>> _Region3(500,650)["h"] + >>> _Region3(500,650).h 1863.43019 >>> p = _Region3(500, 650) - >>> p["h"]-p["P"]*1000*p["v"] + >>> p.h-p.P*1000*p.v 1812.26279 - >>> _Region3(200,650)["s"] + >>> _Region3(200,650).s 4.85438792 - >>> _Region3(200,650)["cp"] + >>> _Region3(200,650).cp 44.6579342 - >>> _Region3(200,650)["cv"] + >>> _Region3(200,650).cv 4.04118076 - >>> _Region3(200,650)["w"] + >>> _Region3(200,650).w 383.444594 - >>> _Region3(500,750)["alfav"] + >>> _Region3(500,750).alfav 0.00441515098 - >>> _Region3(500,750)["kt"] + >>> _Region3(500,750).kt 0.00806710817 """ I = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, @@ -1854,21 +1863,16 @@ def _Region3(rho: float, T: float) -> Dict[str, float]: R = _global_R - propiedades = {} - propiedades["T"] = T - propiedades["P"] = d*gd*R*T*rho/1000 - propiedades["v"] = 1/rho - propiedades["h"] = R*T*(Tr*gt+d*gd) - propiedades["s"] = R*(Tr*gt-g) - propiedades["cp"] = R*(-Tr**2*gtt+(d*gd-d*Tr*gdt)**2/(2*d*gd+d**2*gdd)) - propiedades["cv"] = -R*Tr**2*gtt - propiedades["w"] = sqrt(R*T*1000*(2*d*gd+d**2*gdd-(d*gd-d*Tr*gdt)**2 - / Tr**2/gtt)) - propiedades["alfav"] = (gd-Tr*gdt)/(2*gd+d*gdd)/T - propiedades["kt"] = 1/(2*d*gd+d**2*gdd)/rho/R/T*1000 - propiedades["region"] = 3 - propiedades["x"] = 1 - return propiedades + P = d*gd*R*T*rho/1000 + v = 1/rho + h = R*T*(Tr*gt+d*gd) + s = R*(Tr*gt-g) + cp = R*(-Tr**2*gtt+(d*gd-d*Tr*gdt)**2/(2*d*gd+d**2*gdd)) + cv = -R*Tr**2*gtt + w = sqrt(R*T*1000*(2*d*gd+d**2*gdd-(d*gd-d*Tr*gdt)**2 / Tr**2/gtt)) + alfav = (gd-Tr*gdt)/(2*gd+d*gdd)/T + kt = 1/(2*d*gd+d**2*gdd)/rho/R/T*1000 + return IAPWS97Properties(T, P, v, h, s, cp, cv, w, alfav, kt, 3, 1.0) def _h_3ab(P: float) -> float: @@ -3570,7 +3574,7 @@ def _Backward3x_v_PT(T: float, P: float, x: str) -> float: # Region 4 -def _Region4(P: float, x: float) -> Dict[str, float]: +def _Region4(P: float, x: float) -> IAPWS97Properties: """Basic equation for region 4 Parameters @@ -3602,20 +3606,15 @@ def _Region4(P: float, x: float) -> Dict[str, float]: P1 = _Region1(T, P) P2 = _Region2(T, P) - propiedades: Dict[str, float] = {} - propiedades["T"] = T - propiedades["P"] = P - propiedades["v"] = P1["v"]+x*(P2["v"]-P1["v"]) - propiedades["h"] = P1["h"]+x*(P2["h"]-P1["h"]) - propiedades["s"] = P1["s"]+x*(P2["s"]-P1["s"]) - #propiedades["cp"] = None - #propiedades["cv"] = None - #propiedades["w"] = None - #propiedades["alfav"] = None - #propiedades["kt"] = None - propiedades["region"] = 4 - propiedades["x"] = x - return propiedades + v = P1.v+x*(P2.v-P1.v) + h = P1.h+x*(P2.h-P1.h) + s = P1.s+x*(P2.s-P1.s) + cp = float('nan') + cv = float('nan') + w = float('nan') + alfav = float('nan') + kt = float('nan') + return IAPWS97Properties(T, P, v, h, s, cp, cv, w, alfav, kt, 4, x) def _Backward4_T_hs(h: float, s: float) -> float: @@ -3676,7 +3675,7 @@ def _Backward4_T_hs(h: float, s: float) -> float: # Region 5 -def _Region5(T: float, P: float) -> Dict[str, float]: +def _Region5(T: float, P: float) -> IAPWS97Properties: """Basic equation for region 5 Parameters @@ -3708,23 +3707,23 @@ def _Region5(T: float, P: float) -> Dict[str, float]: Examples -------- - >>> _Region5(1500,0.5)["v"] + >>> _Region5(1500,0.5).v 1.38455090 - >>> _Region5(1500,0.5)["h"] + >>> _Region5(1500,0.5).h 5219.76855 - >>> _Region5(1500,0.5)["h"]-500*_Region5(1500,0.5)["v"] + >>> _Region5(1500,0.5).h-500*_Region5(1500,0.5).v 4527.49310 - >>> _Region5(1500,30)["s"] + >>> _Region5(1500,30).s 7.72970133 - >>> _Region5(1500,30)["cp"] + >>> _Region5(1500,30).cp 2.72724317 - >>> _Region5(1500,30)["cv"] + >>> _Region5(1500,30).cv 2.19274829 - >>> _Region5(2000,30)["w"] + >>> _Region5(2000,30).w 1067.36948 - >>> _Region5(2000,30)["alfav"] + >>> _Region5(2000,30).alfav 0.000508830641 - >>> _Region5(2000,30)["kt"] + >>> _Region5(2000,30).kt 0.0329193892 """ if P < 0: @@ -3750,22 +3749,16 @@ def _Region5(T: float, P: float) -> Dict[str, float]: R = _global_R - propiedades = {} - propiedades["T"] = T - propiedades["P"] = P - propiedades["v"] = Pr*(gop+grp)*R*T/P/1000 - propiedades["h"] = Tr*(got+grt)*R*T - propiedades["s"] = R*(Tr*(got+grt)-(go+gr)) - propiedades["cp"] = -R*Tr**2*(gott+grtt) - propiedades["cv"] = R*(-Tr**2*(gott+grtt)+((gop+grp)-Tr*(gopt+grpt))**2 - / (gopp+grpp)) - propiedades["w"] = (R*T*1000*(1+2*Pr*grp+Pr**2*grp**2)/(1-Pr**2*grpp+( + v = Pr*(gop+grp)*R*T/P/1000 + h = Tr*(got+grt)*R*T + s = R*(Tr*(got+grt)-(go+gr)) + cp = -R*Tr**2*(gott+grtt) + cv = R*(-Tr**2*(gott+grtt)+((gop+grp)-Tr*(gopt+grpt))**2 / (gopp+grpp)) + w = (R*T*1000*(1+2*Pr*grp+Pr**2*grp**2)/(1-Pr**2*grpp+( 1+Pr*grp-Tr*Pr*grpt)**2/Tr**2/(gott+grtt)))**0.5 - propiedades["alfav"] = (1+Pr*grp-Tr*Pr*grpt)/(1+Pr*grp)/T - propiedades["kt"] = (1-Pr**2*grpp)/(1+Pr*grp)/P - propiedades["region"] = 5 - propiedades["x"] = 1 - return propiedades + alfav = (1+Pr*grp-Tr*Pr*grpt)/(1+Pr*grp)/T + kt = (1-Pr**2*grpp)/(1+Pr*grp)/P + return IAPWS97Properties(T, P, v, h, s, cp, cv, w, alfav, kt, 5, 1) def Region5_cp0(Tr: float, Pr: float) -> Tuple[float, float, float, float, float, float]: @@ -3876,11 +3869,11 @@ def _Bound_Ph(P: float, h: float) -> Optional[int]: """ region = None if Pmin <= P <= Ps_623: - h14 = _Region1(_TSat_P(P), P)["h"] - h24 = _Region2(_TSat_P(P), P)["h"] - h25 = _Region2(1073.15, P)["h"] - hmin = _Region1(273.15, P)["h"] - hmax = _Region5(2273.15, P)["h"] + h14 = _Region1(_TSat_P(P), P).h + h24 = _Region2(_TSat_P(P), P).h + h25 = _Region2(1073.15, P).h + hmin = _Region1(273.15, P).h + hmax = _Region5(2273.15, P).h if hmin <= h <= h14: region = 1 elif h14 < h < h24: @@ -3890,11 +3883,11 @@ def _Bound_Ph(P: float, h: float) -> Optional[int]: elif h25 < h <= hmax: region = 5 elif Ps_623 < P < Pc: - hmin = _Region1(273.15, P)["h"] - h13 = _Region1(623.15, P)["h"] - h32 = _Region2(_t_P(P), P)["h"] - h25 = _Region2(1073.15, P)["h"] - hmax = _Region5(2273.15, P)["h"] + hmin = _Region1(273.15, P).h + h13 = _Region1(623.15, P).h + h32 = _Region2(_t_P(P), P).h + h25 = _Region2(1073.15, P).h + hmax = _Region5(2273.15, P).h if hmin <= h <= h13: region = 1 elif h13 < h < h32: @@ -3911,11 +3904,11 @@ def _Bound_Ph(P: float, h: float) -> Optional[int]: elif h25 < h <= hmax: region = 5 elif Pc <= P <= 100: - hmin = _Region1(273.15, P)["h"] - h13 = _Region1(623.15, P)["h"] - h32 = _Region2(_t_P(P), P)["h"] - h25 = _Region2(1073.15, P)["h"] - hmax = _Region5(2273.15, P)["h"] + hmin = _Region1(273.15, P).h + h13 = _Region1(623.15, P).h + h32 = _Region2(_t_P(P), P).h + h25 = _Region2(1073.15, P).h + hmax = _Region5(2273.15, P).h if hmin <= h <= h13: region = 1 elif h13 < h < h32: @@ -3950,11 +3943,11 @@ def _Bound_Ps(P: float, s: float) -> Optional[int]: """ region = None if Pmin <= P <= Ps_623: - smin = _Region1(273.15, P)["s"] - s14 = _Region1(_TSat_P(P), P)["s"] - s24 = _Region2(_TSat_P(P), P)["s"] - s25 = _Region2(1073.15, P)["s"] - smax = _Region5(2273.15, P)["s"] + smin = _Region1(273.15, P).s + s14 = _Region1(_TSat_P(P), P).s + s24 = _Region2(_TSat_P(P), P).s + s25 = _Region2(1073.15, P).s + smax = _Region5(2273.15, P).s if smin <= s <= s14: region = 1 elif s14 < s < s24: @@ -3964,11 +3957,11 @@ def _Bound_Ps(P: float, s: float) -> Optional[int]: elif s25 < s <= smax: region = 5 elif Ps_623 < P < Pc: - smin = _Region1(273.15, P)["s"] - s13 = _Region1(623.15, P)["s"] - s32 = _Region2(_t_P(P), P)["s"] - s25 = _Region2(1073.15, P)["s"] - smax = _Region5(2273.15, P)["s"] + smin = _Region1(273.15, P).s + s13 = _Region1(623.15, P).s + s32 = _Region2(_t_P(P), P).s + s25 = _Region2(1073.15, P).s + smax = _Region5(2273.15, P).s if smin <= s <= s13: region = 1 elif s13 < s < s32: @@ -3985,11 +3978,11 @@ def _Bound_Ps(P: float, s: float) -> Optional[int]: elif s25 < s <= smax: region = 5 elif Pc <= P <= 100: - smin = _Region1(273.15, P)["s"] - s13 = _Region1(623.15, P)["s"] - s32 = _Region2(_t_P(P), P)["s"] - s25 = _Region2(1073.15, P)["s"] - smax = _Region5(2273.15, P)["s"] + smin = _Region1(273.15, P).s + s13 = _Region1(623.15, P).s + s32 = _Region2(_t_P(P), P).s + s25 = _Region2(1073.15, P).s + smax = _Region5(2273.15, P).s if smin <= s <= s13: region = 1 elif s13 < s < s32: @@ -4023,33 +4016,33 @@ def _Bound_hs(h: float, s: float) -> Optional[int]: 2008; doi: 10.1007/978-3-540-74234-0. Fig. 2.14 """ region = None - s13 = _Region1(623.15, 100)["s"] - s13s = _Region1(623.15, Ps_623)["s"] - sTPmax = _Region2(1073.15, 100)["s"] - s2ab = _Region2(1073.15, 4)["s"] + s13 = _Region1(623.15, 100).s + s13s = _Region1(623.15, Ps_623).s + sTPmax = _Region2(1073.15, 100).s + s2ab = _Region2(1073.15, 4).s # Left point in h-s plot - smin = _Region1(273.15, 100)["s"] - hmin = _Region1(273.15, Pmin)["h"] + smin = _Region1(273.15, 100).s + hmin = _Region1(273.15, Pmin).h # Right point in h-s plot _Pmax = _Region2(1073.15, Pmin) - hmax = _Pmax["h"] - smax = _Pmax["s"] + hmax = _Pmax.h + smax = _Pmax.s # Region 4 left and right point _sL = _Region1(273.15, Pmin) - h4l = _sL["h"] - s4l = _sL["s"] + h4l = _sL.h + s4l = _sL.s _sV = _Region2(273.15, Pmin) - h4v = _sV["h"] - s4v = _sV["s"] + h4v = _sV.h + s4v = _sV.s if smin <= s <= s13: hmin = h4l+(s-s4l)/(s4v-s4l)*(h4v-h4l) hs = _h1_s(s) T = _Backward1_T_Ps(100, s)-0.0218 - hmax = _Region1(T, 100)["h"] + hmax = _Region1(T, 100).h if hmin <= h < hs: region = 4 elif hs <= h <= hmax: @@ -4061,7 +4054,7 @@ def _Bound_hs(h: float, s: float) -> Optional[int]: h13 = _h13_s(s) v = _Backward3_v_Ps(100, s)*(1+9.6e-5) T = _Backward3_T_Ps(100, s)-0.0248 - hmax = _Region3(1/v, T)["h"] + hmax = _Region3(1/v, T).h if hmin <= h < hs: region = 4 elif hs <= h < h13: @@ -4074,7 +4067,7 @@ def _Bound_hs(h: float, s: float) -> Optional[int]: hs = _h3a_s(s) v = _Backward3_v_Ps(100, s)*(1+9.6e-5) T = _Backward3_T_Ps(100, s)-0.0248 - hmax = _Region3(1/v, T)["h"] + hmax = _Region3(1/v, T).h if hmin <= h < hs: region = 4 elif hs <= h <= hmax: @@ -4085,7 +4078,7 @@ def _Bound_hs(h: float, s: float) -> Optional[int]: hs = _h2c3b_s(s) v = _Backward3_v_Ps(100, s)*(1+9.6e-5) T = _Backward3_T_Ps(100, s)-0.0248 - hmax = _Region3(1/v, T)["h"] + hmax = _Region3(1/v, T).h if hmin <= h < hs: region = 4 elif hs <= h <= hmax: @@ -4095,10 +4088,10 @@ def _Bound_hs(h: float, s: float) -> Optional[int]: # Specific zone with 2-3 boundary in s shape hmin = h4l+(s-s4l)/(s4v-s4l)*(h4v-h4l) hs = _h2c3b_s(s) - h23max = _Region2(863.15, 100)["h"] - h23min = _Region2(623.15, Ps_623)["h"] + h23max = _Region2(863.15, 100).h + h23min = _Region2(623.15, Ps_623).h T = _Backward2_T_Ps(100, s)-0.019 - hmax = _Region2(T, 100)["h"] + hmax = _Region2(T, 100).h if hmin <= h < hs: region = 4 @@ -4116,7 +4109,7 @@ def _Bound_hs(h: float, s: float) -> Optional[int]: hmin = h4l+(s-s4l)/(s4v-s4l)*(h4v-h4l) hs = _h2c3b_s(s) T = _Backward2_T_Ps(100, s)-0.019 - hmax = _Region2(T, 100)["h"] + hmax = _Region2(T, 100).h if hmin <= h < hs: region = 4 elif hs <= h <= hmax: @@ -4126,7 +4119,7 @@ def _Bound_hs(h: float, s: float) -> Optional[int]: hmin = h4l+(s-s4l)/(s4v-s4l)*(h4v-h4l) hs = _h2ab_s(s) T = _Backward2_T_Ps(100, s)-0.019 - hmax = _Region2(T, 100)["h"] + hmax = _Region2(T, 100).h if hmin <= h < hs: region = 4 elif hs <= h <= hmax: @@ -4136,7 +4129,7 @@ def _Bound_hs(h: float, s: float) -> Optional[int]: hmin = h4l+(s-s4l)/(s4v-s4l)*(h4v-h4l) hs = _h2ab_s(s) P = _Backward2_P_hs(h, s) - hmax = _Region2(1073.15, P)["h"] + hmax = _Region2(1073.15, P).h if hmin <= h < hs: region = 4 elif hs <= h <= hmax: @@ -4146,26 +4139,26 @@ def _Bound_hs(h: float, s: float) -> Optional[int]: hmin = h4l+(s-s4l)/(s4v-s4l)*(h4v-h4l) hs = _h2ab_s(s) P = _Backward2_P_hs(h, s) - hmax = _Region2(1073.15, P)["h"] + hmax = _Region2(1073.15, P).h if hmin <= h < hs: region = 4 elif hs <= h <= hmax: region = 2 elif s4v <= s <= smax: - hmin = _Region2(273.15, Pmin)["h"] + hmin = _Region2(273.15, Pmin).h P = _Backward2a_P_hs(h, s) - hmax = _Region2(1073.15, P)["h"] + hmax = _Region2(1073.15, P).h if Pmin <= P <= 100 and hmin <= h <= hmax: region = 2 # Check region 5 if not region and \ - _Region5(1073.15, 50)["s"] < s <= _Region5(2273.15, Pmin)["s"] \ - and _Region5(1073.15, 50)["h"] < h <= _Region5(2273.15, Pmin)["h"]: + _Region5(1073.15, 50).s < s <= _Region5(2273.15, Pmin).s \ + and _Region5(1073.15, 50).h < h <= _Region5(2273.15, Pmin).h: def funcion(par: Tuple[float, float]) -> Tuple[float, float]: - return (_Region5(par[0], par[1])["h"]-h, - _Region5(par[0], par[1])["s"]-s) + return (_Region5(par[0], par[1]).h-h, + _Region5(par[0], par[1]).s-s) T, P = tuple(map(float, fsolve(funcion, [1400, 1]))) if 1073.15 < T <= 2273.15 and Pmin <= P <= 50: region = 5 @@ -4381,7 +4374,6 @@ def calculable(self) -> str: def calculo(self) -> None: """Calculate procedure""" - propiedades: Dict[str, float] = {} arg1: float = self.kwargs[self._thermo[0]] # type: ignore arg2: float = self.kwargs[self._thermo[1]] # type: ignore args = (arg1, arg2) @@ -4400,7 +4392,7 @@ def calculo(self) -> None: def rho_funcion(rho: float) -> float: assert(self.kwargs["T"] is not None) - return _Region3(rho, self.kwargs["T"])["P"]-P + return _Region3(rho, self.kwargs["T"]).P-P rho = float(newton(rho_funcion, 1/vo)) propiedades = _Region3(rho, T) elif region == 5: @@ -4413,26 +4405,26 @@ def rho_funcion(rho: float) -> float: region = _Bound_Ph(P, h) if region == 1: To = _Backward1_T_Ph(P, h) - T = float(newton(lambda T: _Region1(T, P)["h"]-h, To)) + T = float(newton(lambda T: _Region1(T, P).h-h, To)) propiedades = _Region1(T, P) elif region == 2: To = _Backward2_T_Ph(P, h) - T = float(newton(lambda T: _Region2(T, P)["h"]-h, To)) + T = float(newton(lambda T: _Region2(T, P).h-h, To)) propiedades = _Region2(T, P) elif region == 3: vo = _Backward3_v_Ph(P, h) To = _Backward3_T_Ph(P, h) def funcion(par: Tuple[float, float]) -> Tuple[float, float]: - return (_Region3(par[0], par[1])["h"]-h, - _Region3(par[0], par[1])["P"]-P) + return (_Region3(par[0], par[1]).h-h, + _Region3(par[0], par[1]).P-P) rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) propiedades = _Region3(rho, T) elif region == 4: T = _TSat_P(P) if T <= 623.15: - h1 = _Region1(T, P)["h"] - h2 = _Region2(T, P)["h"] + h1 = _Region1(T, P).h + h2 = _Region2(T, P).h x = (h-h1)/(h2-h1) propiedades = _Region4(P, x) else: @@ -4440,12 +4432,12 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: To = _Backward3_T_Ph(P, h) def funcion(par: Tuple[float, float]) -> Tuple[float, float]: - return (_Region3(par[0], par[1])["h"]-h, - _Region3(par[0], par[1])["P"]-P) + return (_Region3(par[0], par[1]).h-h, + _Region3(par[0], par[1]).P-P) rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) propiedades = _Region3(rho, T) elif region == 5: - T = float(newton(lambda T: _Region5(T, P)["h"]-h, 1500)) + T = float(newton(lambda T: _Region5(T, P).h-h, 1500)) propiedades = _Region5(T, P) else: raise NotImplementedError("Incoming out of bound") @@ -4455,26 +4447,26 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: region = _Bound_Ps(P, s) if region == 1: To = _Backward1_T_Ps(P, s) - T = float(newton(lambda T: _Region1(T, P)["s"]-s, To)) + T = float(newton(lambda T: _Region1(T, P).s-s, To)) propiedades = _Region1(T, P) elif region == 2: To = _Backward2_T_Ps(P, s) - T = float(newton(lambda T: _Region2(T, P)["s"]-s, To)) + T = float(newton(lambda T: _Region2(T, P).s-s, To)) propiedades = _Region2(T, P) elif region == 3: vo = _Backward3_v_Ps(P, s) To = _Backward3_T_Ps(P, s) def funcion(par: Tuple[float, float]) -> Tuple[float, float]: - return (_Region3(par[0], par[1])["s"]-s, - _Region3(par[0], par[1])["P"]-P) + return (_Region3(par[0], par[1]).s-s, + _Region3(par[0], par[1]).P-P) rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) propiedades = _Region3(rho, T) elif region == 4: T = _TSat_P(P) if T <= 623.15: - s1 = _Region1(T, P)["s"] - s2 = _Region2(T, P)["s"] + s1 = _Region1(T, P).s + s2 = _Region2(T, P).s x = (s-s1)/(s2-s1) propiedades = _Region4(P, x) else: @@ -4482,12 +4474,12 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: To = _Backward3_T_Ps(P, s) def funcion(par: Tuple[float, float]) -> Tuple[float, float]: - return (_Region3(par[0], par[1])["s"]-s, - _Region3(par[0], par[1])["P"]-P) + return (_Region3(par[0], par[1]).s-s, + _Region3(par[0], par[1]).P-P) rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) propiedades = _Region3(rho, T) elif region == 5: - T = float(newton(lambda T: _Region5(T, P)["s"]-s, 1500)) + T = float(newton(lambda T: _Region5(T, P).s-s, 1500)) propiedades = _Region5(T, P) else: raise NotImplementedError("Incoming out of bound") @@ -4500,8 +4492,8 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: To = _Backward1_T_Ph(Po, h) def funcion(par: Tuple[float, float]) -> Tuple[float, float]: - return (_Region1(par[0], par[1])["h"]-h, - _Region1(par[0], par[1])["s"]-s) + return (_Region1(par[0], par[1]).h-h, + _Region1(par[0], par[1]).s-s) T, P = tuple(map(float, fsolve(funcion, [To, Po]))) propiedades = _Region1(T, P) elif region == 2: @@ -4509,8 +4501,8 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: To = _Backward2_T_Ph(Po, h) def funcion(par: Tuple[float, float]) -> Tuple[float, float]: - return (_Region2(par[0], par[1])["h"]-h, - _Region2(par[0], par[1])["s"]-s) + return (_Region2(par[0], par[1]).h-h, + _Region2(par[0], par[1]).s-s) T, P = tuple(map(float, fsolve(funcion, [To, Po]))) propiedades = _Region2(T, P) elif region == 3: @@ -4519,8 +4511,8 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: To = _Backward3_T_Ph(P, h) def funcion(par: Tuple[float, float]) -> Tuple[float, float]: - return (_Region3(par[0], par[1])["h"]-h, - _Region3(par[0], par[1])["s"]-s) + return (_Region3(par[0], par[1]).h-h, + _Region3(par[0], par[1]).s-s) rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) propiedades = _Region3(rho, T) elif region == 4: @@ -4558,10 +4550,10 @@ def funcion2(par: List[float]) -> Tuple[float, float]: Po = _PSat_T(pp0) liquid = _Region1(pp0, Po) vapor = _Region2(pp0, Po) - hl = liquid["h"] - sl = liquid["s"] - hv = vapor["h"] - sv = vapor["s"] + hl = liquid.h + sl = liquid.s + hv = vapor.h + sv = vapor.s return (hv*pp1+hl*(1-pp1)-h, sv*pp1+sl*(1-pp1)-s) T, x = tuple(map(float, fsolve(funcion2, [To, 0.5]))) @@ -4573,8 +4565,8 @@ def funcion2(par: List[float]) -> Tuple[float, float]: propiedades = _Region1(T, P) elif region == 5: def funcion(par: Tuple[float, float]) -> Tuple[float, float]: - return (_Region5(par[0], par[1])["h"]-h, - _Region5(par[0], par[1])["s"]-s) + return (_Region5(par[0], par[1]).h-h, + _Region5(par[0], par[1]).s-s) T, P = tuple(map(float, fsolve(funcion, [1400, 1]))) propiedades = _Region5(T, P) else: @@ -4591,7 +4583,7 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: propiedades = _Region2(T, P) elif Ps_623 < P < Pc and x in (0, 1): def rho_funcion(rho: float) -> float: - return _Region3(rho, T)["P"]-P + return _Region3(rho, T).P-P rhoo = 1./_Backward3_sat_v_P(P, T, int(x)) rho = float(fsolve(rho_funcion, rhoo)[0]) propiedades = _Region3(rho, T) @@ -4600,7 +4592,7 @@ def rho_funcion(rho: float) -> float: else: raise NotImplementedError("Incoming out of bound") self.sigma = _Tension(T) - propiedades["x"] = x + propiedades.x = x elif self._thermo == "Tx": T, x = args @@ -4619,7 +4611,7 @@ def rho_funcion(rho: float) -> float: else: raise NotImplementedError("Incoming out of bound") self.sigma = _Tension(T) - propiedades["x"] = x + propiedades.x = x self.M = 18.015257 # kg/kmol self.Pc = Pc @@ -4630,15 +4622,15 @@ def rho_funcion(rho: float) -> float: self.f_accent = f_acent self.dipole = Dipole - self.x = propiedades["x"] - self.region = int(propiedades["region"]) + self.x = propiedades.x + self.region = propiedades.region self.name = "water" self.synonim = "R-718" self.CAS = "7732-18-5" - self.T = propiedades["T"] - self.P = propiedades["P"] - self.v = propiedades["v"] + self.T = propiedades.T + self.P = propiedades.P + self.v = propiedades.v self.rho = 1/self.v self.phase = getphase(self.Tc, self.Pc, self.T, self.P, self.x, self.region) @@ -4692,35 +4684,35 @@ def rho_funcion(rho: float) -> float: vapor = _Region2(self.T, self.P) self.fill(self.Vapor, vapor) - self.h = propiedades["h"] + self.h = propiedades.h self.u = self.h-self.P*1000*self.v - self.s = propiedades["s"] + self.s = propiedades.s self.a = self.u-self.T*self.s self.g = self.h-self.T*self.s self.sigma = _Tension(self.T) - self.Hvap = vapor["h"]-liquido["h"] - self.Svap = vapor["s"]-liquido["s"] + self.Hvap = vapor.h-liquido.h + self.Svap = vapor.s-liquido.s - def fill(self, fase: _fase, estado: Dict[str, float]) -> None: + def fill(self, fase: _fase, estado: IAPWS97Properties) -> None: """Fill phase properties""" - fase.v = estado["v"] + fase.v = estado.v fase.rho = 1/fase.v - fase.h = estado["h"] - fase.s = estado["s"] + fase.h = estado.h + fase.s = estado.s fase.u = fase.h-self.P*1000*fase.v fase.a = fase.u-self.T*fase.s fase.g = fase.h-self.T*fase.s - fase.cv = estado["cv"] - fase.cp = estado["cp"] + fase.cv = estado.cv + fase.cp = estado.cp fase.cp_cv = fase.cp/fase.cv - fase.w = estado["w"] + fase.w = estado.w fase.Z = self.P*fase.v/_global_R*1000/self.T - fase.alfav = estado["alfav"] - fase.xkappa = estado["kt"] + fase.alfav = estado.alfav + fase.xkappa = estado.kt fase.kappas = -1/fase.v*self.derivative("v", "P", "s", fase) fase.joule = self.derivative("T", "P", "h", fase) diff --git a/test.py b/test.py index 43fe229..3d874d4 100755 --- a/test.py +++ b/test.py @@ -270,10 +270,10 @@ def test_ThCond(self) -> None: self.assertEqual(round(fluid97.k*1000, 7), 52.2311024) fluid97 = IAPWS97(T=800, P=50) self.assertEqual(round(fluid97.k*1000, 6), 177.709914) - P = _Region3(T=647.35, rho=222)["P"] + P = _Region3(T=647.35, rho=222).P fluid97 = IAPWS97(T=647.35, P=P) self.assertEqual(round(fluid97.k*1000, 6), 366.879411) - P = _Region3(T=647.35, rho=322)["P"] + P = _Region3(T=647.35, rho=322).P fluid97 = IAPWS97(T=647.35, P=P) self.assertEqual(round(fluid97.k*1000, 5), 1241.82415) @@ -507,28 +507,28 @@ def test_auxiliarySaturation(self) -> None: def test_IAPWS97_1(self) -> None: """Table 5, pag 9""" fluid = _Region1(300, 3) - self.assertEqual(round(fluid["v"], 11), 0.00100215168) - self.assertEqual(round(fluid["h"], 6), 115.331273) - self.assertEqual(round(fluid["h"]-fluid["P"]*1000*fluid["v"], 6), 112.324818) - self.assertEqual(round(fluid["s"], 9), 0.392294792) - self.assertEqual(round(fluid["cp"], 8), 4.17301218) - self.assertEqual(round(fluid["w"], 5), 1507.73921) + self.assertEqual(round(fluid.v, 11), 0.00100215168) + self.assertEqual(round(fluid.h, 6), 115.331273) + self.assertEqual(round(fluid.h-fluid.P*1000*fluid.v, 6), 112.324818) + self.assertEqual(round(fluid.s, 9), 0.392294792) + self.assertEqual(round(fluid.cp, 8), 4.17301218) + self.assertEqual(round(fluid.w, 5), 1507.73921) fluid = _Region1(300, 80) - self.assertEqual(round(fluid["v"], 12), 0.000971180894) - self.assertEqual(round(fluid["h"], 6), 184.142828) - self.assertEqual(round(fluid["h"]-fluid["P"]*1000*fluid["v"], 6), 106.448356) - self.assertEqual(round(fluid["s"], 9), 0.368563852) - self.assertEqual(round(fluid["cp"], 8), 4.01008987) - self.assertEqual(round(fluid["w"], 5), 1634.69054) + self.assertEqual(round(fluid.v, 12), 0.000971180894) + self.assertEqual(round(fluid.h, 6), 184.142828) + self.assertEqual(round(fluid.h-fluid.P*1000*fluid.v, 6), 106.448356) + self.assertEqual(round(fluid.s, 9), 0.368563852) + self.assertEqual(round(fluid.cp, 8), 4.01008987) + self.assertEqual(round(fluid.w, 5), 1634.69054) fluid = _Region1(500, 3) - self.assertEqual(round(fluid["v"], 10), 0.0012024180) - self.assertEqual(round(fluid["h"], 6), 975.542239) - self.assertEqual(round(fluid["h"]-fluid["P"]*1000*fluid["v"], 6), 971.934985) - self.assertEqual(round(fluid["s"], 9), 2.58041912) - self.assertEqual(round(fluid["cp"], 8), 4.65580682) - self.assertEqual(round(fluid["w"], 5), 1240.71337) + self.assertEqual(round(fluid.v, 10), 0.0012024180) + self.assertEqual(round(fluid.h, 6), 975.542239) + self.assertEqual(round(fluid.h-fluid.P*1000*fluid.v, 6), 971.934985) + self.assertEqual(round(fluid.s, 9), 2.58041912) + self.assertEqual(round(fluid.cp, 8), 4.65580682) + self.assertEqual(round(fluid.w, 5), 1240.71337) # _Backward1_T_Ph Table 7 pag 11 self.assertEqual(round(_Backward1_T_Ph(3, 500), 6), 391.798509) @@ -557,28 +557,28 @@ def test_IAPWS97_2(self) -> None: self.assertEqual(round(_hab_s(7), 6), 3376.437884) fluid = _Region2(300, 0.0035) - self.assertEqual(round(fluid["v"], 7), 39.4913866) - self.assertEqual(round(fluid["h"], 5), 2549.91145) - self.assertEqual(round(fluid["h"]-fluid["P"]*1000*fluid["v"], 5), 2411.69160) - self.assertEqual(round(fluid["s"], 8), 8.52238967) - self.assertEqual(round(fluid["cp"], 8), 1.91300162) - self.assertEqual(round(fluid["w"], 6), 427.920172) + self.assertEqual(round(fluid.v, 7), 39.4913866) + self.assertEqual(round(fluid.h, 5), 2549.91145) + self.assertEqual(round(fluid.h-fluid.P*1000*fluid.v, 5), 2411.69160) + self.assertEqual(round(fluid.s, 8), 8.52238967) + self.assertEqual(round(fluid.cp, 8), 1.91300162) + self.assertEqual(round(fluid.w, 6), 427.920172) fluid = _Region2(700, 0.0035) - self.assertEqual(round(fluid["v"], 7), 92.3015898) - self.assertEqual(round(fluid["h"], 5), 3335.68375) - self.assertEqual(round(fluid["h"]-fluid["P"]*1000*fluid["v"], 5), 3012.62819) - self.assertEqual(round(fluid["s"], 7), 10.1749996) - self.assertEqual(round(fluid["cp"], 8), 2.08141274) - self.assertEqual(round(fluid["w"], 6), 644.289068) + self.assertEqual(round(fluid.v, 7), 92.3015898) + self.assertEqual(round(fluid.h, 5), 3335.68375) + self.assertEqual(round(fluid.h-fluid.P*1000*fluid.v, 5), 3012.62819) + self.assertEqual(round(fluid.s, 7), 10.1749996) + self.assertEqual(round(fluid.cp, 8), 2.08141274) + self.assertEqual(round(fluid.w, 6), 644.289068) fluid = _Region2(700, 30) - self.assertEqual(round(fluid["v"], 11), 0.00542946619) - self.assertEqual(round(fluid["h"], 5), 2631.49474) - self.assertEqual(round(fluid["h"]-fluid["P"]*1000*fluid["v"], 5), 2468.61076) - self.assertEqual(round(fluid["s"], 8), 5.17540298) - self.assertEqual(round(fluid["cp"], 7), 10.3505092) - self.assertEqual(round(fluid["w"], 6), 480.386523) + self.assertEqual(round(fluid.v, 11), 0.00542946619) + self.assertEqual(round(fluid.h, 5), 2631.49474) + self.assertEqual(round(fluid.h-fluid.P*1000*fluid.v, 5), 2468.61076) + self.assertEqual(round(fluid.s, 8), 5.17540298) + self.assertEqual(round(fluid.cp, 7), 10.3505092) + self.assertEqual(round(fluid.w, 6), 480.386523) # Backward2_T_Ph Table 24 pag 25 self.assertEqual(round(_Backward2_T_Ph(0.001, 3000), 6), 534.433241) @@ -616,28 +616,28 @@ def test_IAPWS97_2(self) -> None: def test_IAPWS97_3(self) -> None: """Table 33, pag 49""" fluid = _Region3(500, 650) - self.assertEqual(round(fluid["P"], 7), 25.5837018) - self.assertEqual(round(fluid["h"], 5), 1863.43019) - self.assertEqual(round(fluid["h"]-fluid["P"]*1000*fluid["v"], 5), 1812.26279) - self.assertEqual(round(fluid["s"], 8), 4.05427273) - self.assertEqual(round(fluid["cp"], 7), 13.8935717) - self.assertEqual(round(fluid["w"], 6), 502.005554) + self.assertEqual(round(fluid.P, 7), 25.5837018) + self.assertEqual(round(fluid.h, 5), 1863.43019) + self.assertEqual(round(fluid.h-fluid.P*1000*fluid.v, 5), 1812.26279) + self.assertEqual(round(fluid.s, 8), 4.05427273) + self.assertEqual(round(fluid.cp, 7), 13.8935717) + self.assertEqual(round(fluid.w, 6), 502.005554) fluid = _Region3(200, 650) - self.assertEqual(round(fluid["P"], 7), 22.2930643) - self.assertEqual(round(fluid["h"], 5), 2375.12401) - self.assertEqual(round(fluid["h"]-fluid["P"]*1000*fluid["v"], 5), 2263.65868) - self.assertEqual(round(fluid["s"], 8), 4.85438792) - self.assertEqual(round(fluid["cp"], 7), 44.6579342) - self.assertEqual(round(fluid["w"], 6), 383.444594) + self.assertEqual(round(fluid.P, 7), 22.2930643) + self.assertEqual(round(fluid.h, 5), 2375.12401) + self.assertEqual(round(fluid.h-fluid.P*1000*fluid.v, 5), 2263.65868) + self.assertEqual(round(fluid.s, 8), 4.85438792) + self.assertEqual(round(fluid.cp, 7), 44.6579342) + self.assertEqual(round(fluid.w, 6), 383.444594) fluid = _Region3(500, 750) - self.assertEqual(round(fluid["P"], 7), 78.3095639) - self.assertEqual(round(fluid["h"], 5), 2258.68845) - self.assertEqual(round(fluid["h"]-fluid["P"]*1000*fluid["v"], 5), 2102.06932) - self.assertEqual(round(fluid["s"], 8), 4.46971906) - self.assertEqual(round(fluid["cp"], 8), 6.34165359) - self.assertEqual(round(fluid["w"], 6), 760.696041) + self.assertEqual(round(fluid.P, 7), 78.3095639) + self.assertEqual(round(fluid.h, 5), 2258.68845) + self.assertEqual(round(fluid.h-fluid.P*1000*fluid.v, 5), 2102.06932) + self.assertEqual(round(fluid.s, 8), 4.46971906) + self.assertEqual(round(fluid.cp, 8), 6.34165359) + self.assertEqual(round(fluid.w, 6), 760.696041) # _h_3ab pag 7 self.assertEqual(round(_h_3ab(25), 6), 2095.936454) @@ -826,28 +826,28 @@ def test_IAPWS97_4(self) -> None: def test_IAPWS97_5(self) -> None: """Table 42, pag 40""" fluid = _Region5(1500, 0.5) - self.assertEqual(round(fluid["v"], 8), 1.38455090) - self.assertEqual(round(fluid["h"], 5), 5219.76855) - self.assertEqual(round(fluid["h"]-fluid["P"]*1000*fluid["v"], 5), 4527.49310) - self.assertEqual(round(fluid["s"], 8), 9.65408875) - self.assertEqual(round(fluid["cp"], 8), 2.61609445) - self.assertEqual(round(fluid["w"], 6), 917.068690) + self.assertEqual(round(fluid.v, 8), 1.38455090) + self.assertEqual(round(fluid.h, 5), 5219.76855) + self.assertEqual(round(fluid.h-fluid.P*1000*fluid.v, 5), 4527.49310) + self.assertEqual(round(fluid.s, 8), 9.65408875) + self.assertEqual(round(fluid.cp, 8), 2.61609445) + self.assertEqual(round(fluid.w, 6), 917.068690) fluid = _Region5(1500, 30) - self.assertEqual(round(fluid["v"], 10), 0.0230761299) - self.assertEqual(round(fluid["h"], 5), 5167.23514) - self.assertEqual(round(fluid["h"]-fluid["P"]*1000*fluid["v"], 5), 4474.95124) - self.assertEqual(round(fluid["s"], 8), 7.72970133) - self.assertEqual(round(fluid["cp"], 8), 2.72724317) - self.assertEqual(round(fluid["w"], 6), 928.548002) + self.assertEqual(round(fluid.v, 10), 0.0230761299) + self.assertEqual(round(fluid.h, 5), 5167.23514) + self.assertEqual(round(fluid.h-fluid.P*1000*fluid.v, 5), 4474.95124) + self.assertEqual(round(fluid.s, 8), 7.72970133) + self.assertEqual(round(fluid.cp, 8), 2.72724317) + self.assertEqual(round(fluid.w, 6), 928.548002) fluid = _Region5(2000, 30) - self.assertEqual(round(fluid["v"], 10), 0.0311385219) - self.assertEqual(round(fluid["h"], 5), 6571.22604) - self.assertEqual(round(fluid["h"]-fluid["P"]*1000*fluid["v"], 5), 5637.07038) - self.assertEqual(round(fluid["s"], 8), 8.53640523) - self.assertEqual(round(fluid["cp"], 8), 2.88569882) - self.assertEqual(round(fluid["w"], 5), 1067.36948) + self.assertEqual(round(fluid.v, 10), 0.0311385219) + self.assertEqual(round(fluid.h, 5), 6571.22604) + self.assertEqual(round(fluid.h-fluid.P*1000*fluid.v, 5), 5637.07038) + self.assertEqual(round(fluid.s, 8), 8.53640523) + self.assertEqual(round(fluid.cp, 8), 2.88569882) + self.assertEqual(round(fluid.w, 5), 1067.36948) def test_IAPWS97_custom(self) -> None: """Cycle input parameter from selected point for IAPWS97""" From 00d5b3abcbbff5f0b82b6b6d17118c1acb13f869 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Thu, 18 Mar 2021 01:13:31 -0400 Subject: [PATCH 091/102] Convert MEoS properties to a custom class. More static typing and readability improvements. --- iapws/humidAir.py | 2 +- iapws/iapws95.py | 120 +++++++++++++++++++++++----------------------- test.py | 24 +++++----- 3 files changed, 73 insertions(+), 73 deletions(-) diff --git a/iapws/humidAir.py b/iapws/humidAir.py index cc5fa67..1f86691 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -500,7 +500,7 @@ def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: ref = Air() st = ref._Helmholtz(rho, Tref) - drho = 1e3/self.R/Tref/(1+2*delta*st["fird"]+delta**2*st["firdd"]) + drho = 1e3/self.R/Tref/(1+2*delta*st.fird+delta**2*st.firdd) Xref = self.Pc*rho/rhoc**2*drho diff --git a/iapws/iapws95.py b/iapws/iapws95.py index c22022c..1de7305 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -269,6 +269,25 @@ def _phirt(tau: float, delta: float, coef: Dict[str, List[float]]) -> float: return firt +class MEoSProperties(object): + """The properties required to fill a MEoS phase.""" + + def __init__(self, rho: float, P: float, h: float, s: float, cv: + float, alfap: float, betap: float, fir: float, fird: + float, firdd: float, delta: float) -> None: + self.rho = rho + self.P = P + self.h = h + self.s = s + self.cv = cv + self.alfap = alfap + self.betap = betap + self.fir = fir + self.fird = fird + self.firdd = firdd + self.delta = delta + + class MEoS(_fase): r""" General implementation of multiparameter equation of state. From this @@ -571,8 +590,6 @@ def calculo(self) -> None: rhoc = self._constants.get("rhoref", [self.rhoc])[0] Tc = self._constants.get("Tref", [self.Tc])[0] - propiedades: Dict[str, float] = {} - if self._mode not in ("Tx", "Px"): # Method with iteration necessary to get x if self._mode == "TP": @@ -648,8 +665,8 @@ def rho_func(rho: float) -> float: rhol, rhov, Ps = self._saturation(T) vapor = self._Helmholtz(rhov, T) liquido = self._Helmholtz(rhol, T) - hv = vapor["h"] - hl = liquido["h"] + hv = vapor.h + hl = liquido.h x = (h-hl)/(hv-hl) rho = 1/(x/rhov+(1-x)/rhol) P = Ps/1000 @@ -697,8 +714,8 @@ def rho_func(rho: float) -> float: rhol, rhov, Ps = self._saturation(T) vapor = self._Helmholtz(rhov, T) liquido = self._Helmholtz(rhol, T) - sv = vapor["s"] - sl = liquido["s"] + sv = vapor.s + sl = liquido.s x = (s-sl)/(sv-sl) rho = 1/(x/rhov+(1-x)/rhol) P = Ps/1000 @@ -747,8 +764,8 @@ def rho_func(rho: float) -> float: rhol, rhov, Ps = self._saturation(T) vapor = self._Helmholtz(rhov, T) liquido = self._Helmholtz(rhol, T) - uv = vapor["h"]-vapor["P"]/rhov - ul = liquido["h"]-liquido["P"]/rhol + uv = vapor.h-vapor.P/rhov + ul = liquido.h-liquido.P/rhol x = (u-ul)/(uv-ul) rho = 1/(x/rhov-(1-x)/rhol) P = Ps/1000 @@ -811,7 +828,7 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: liquido = self._Helmholtz(rhoL, T) vapor = self._Helmholtz(rhoG, T) P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( - liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 + liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 elif self._mode == "Ph": def f2(parr: Tuple[float, float]) -> Tuple[float, float]: @@ -874,7 +891,7 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ liquido = self._Helmholtz(rhoL, T) vapor = self._Helmholtz(rhoG, T) P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( - liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 + liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 elif self._mode == "Ps": try: @@ -905,13 +922,13 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: vapor = self._Helmholtz(rhov, T) liquido = self._Helmholtz(rhol, T) x = (1./rho-1/rhol)/(1/rhov-1/rhol) - return Ps-P*1000, vapor["s"]*x+liquido["s"]*(1-x)-s + return Ps-P*1000, vapor.s*x+liquido.s*(1-x)-s rho, T = tuple(map(float, fsolve(f2, [2., 500.]))) rhol, rhov, Ps = self._saturation(T) vapor = self._Helmholtz(rhov, T) liquido = self._Helmholtz(rhol, T) - sv = vapor["s"] - sl = liquido["s"] + sv = vapor.s + sl = liquido.s x = (s-sl)/(sv-sl) elif self._mode == "Pu": @@ -979,7 +996,7 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ liquido = self._Helmholtz(rhoL, T) vapor = self._Helmholtz(rhoG, T) P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( - liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 + liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 elif self._mode == "rhoh": delta = rho/rhoc @@ -1040,7 +1057,7 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: liquido = self._Helmholtz(rhoL, T) vapor = self._Helmholtz(rhoG, T) P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( - liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 + liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 elif self._mode == "rhos": delta = rho/rhoc @@ -1103,7 +1120,7 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: liquido = self._Helmholtz(rhoL, T) vapor = self._Helmholtz(rhoG, T) P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( - liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 + liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 elif self._mode == "rhou": delta = rho/rhoc @@ -1168,7 +1185,7 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: liquido = self._Helmholtz(rhoL, T) vapor = self._Helmholtz(rhoG, T) P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( - liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 + liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 elif self._mode == "hs": def f2(parr: Tuple[float, float]) -> Tuple[float, float]: @@ -1233,7 +1250,7 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ liquido = self._Helmholtz(rhoL, T) vapor = self._Helmholtz(rhoG, T) P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( - liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 + liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 elif self._mode == "hu": def f2(parr: Tuple[float, float]) -> Tuple[float, float]: @@ -1301,7 +1318,7 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ liquido = self._Helmholtz(rhoL, T) vapor = self._Helmholtz(rhoG, T) P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( - liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 + liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 elif self._mode == "su": def f2(parr: Tuple[float, float]) -> Tuple[float, float]: @@ -1375,7 +1392,7 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ liquido = self._Helmholtz(rhoL, T) vapor = self._Helmholtz(rhoG, T) P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( - liquido["fir"]-vapor["fir"]+log(rhoL/rhoG))/1000 + liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 elif self._mode == "Trho": if T < self.Tc: @@ -1399,7 +1416,7 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ x = 0 if not P: - P = propiedades["P"]/1000. + P = propiedades.P/1000. elif self._mode == "Tx": # Check input T in saturation range @@ -1502,8 +1519,8 @@ def t_func(T: float) -> float: self.virialC = vir["C"]/self.rhoc**2 if 0 < x < 1: - self.Hvap = vapor["h"]-liquido["h"] - self.Svap = vapor["s"]-liquido["s"] + self.Hvap = vapor.h-liquido.h + self.Svap = vapor.s-liquido.s else: self.Hvap = None self.Svap = None @@ -1533,35 +1550,25 @@ def _visco(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: raise NotImplementedError - def fill(self, fase: _fase, estado: Dict[str, float]) -> None: + def fill(self, fase: _fase, estado: MEoSProperties) -> None: """Fill phase properties""" - assert("rho" in estado and isinstance(estado["rho"], float)) - assert("h" in estado and isinstance(estado["h"], float)) - assert("s" in estado and isinstance(estado["s"], float)) - assert("fir" in estado and isinstance(estado["fir"], float)) - assert("fird" in estado and isinstance(estado["fird"], float)) - assert("delta" in estado and isinstance(estado["delta"], float)) - assert("cv" in estado and isinstance(estado["cv"], float)) - assert("alfap" in estado and isinstance(estado["alfap"], float)) - assert("betap" in estado and isinstance(estado["betap"], float)) - - fase.rho = estado["rho"] + fase.rho = estado.rho fase.v = 1/fase.rho assert(isinstance(self.M, float)) assert(isinstance(self.R, float)) - fase.h = estado["h"] - fase.s = estado["s"] + fase.h = estado.h + fase.s = estado.s fase.u = fase.h-self.P*1000*fase.v fase.a = fase.u-self.T*fase.s fase.g = fase.h-self.T*fase.s fase.Z = self.P*fase.v/self.T/self.R*1e3 - fase.fi = exp(estado["fir"]+estado["delta"]*estado["fird"] - - log(1+estado["delta"]*estado["fird"])) + fase.fi = exp(estado.fir+estado.delta*estado.fird + - log(1+estado.delta*estado.fird)) fase.f = fase.fi*self.P - fase.cv = estado["cv"] + fase.cv = estado.cv fase.rhoM = fase.rho/self.M fase.hM = fase.h*self.M @@ -1570,8 +1577,8 @@ def fill(self, fase: _fase, estado: Dict[str, float]) -> None: fase.aM = fase.a*self.M fase.gM = fase.g*self.M - fase.alfap = estado["alfap"] - fase.betap = estado["betap"] + fase.alfap = estado.alfap + fase.betap = estado.betap fase.cp = self.derivative("h", "T", "P", fase) fase.cp_cv = fase.cp/fase.cv @@ -1669,7 +1676,7 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: Ps = self.R*T*rhoL*rhoG/(rhoL-rhoG)*(firL-firG+log(deltaL/deltaG)) return rhoL, rhoG, Ps - def _Helmholtz(self, rho: float, T: float) -> Dict[str, float]: + def _Helmholtz(self, rho: float, T: float) -> MEoSProperties: """Calculated properties from helmholtz free energy and derivatives Parameters @@ -1713,21 +1720,14 @@ def _Helmholtz(self, rho: float, T: float) -> Dict[str, float]: res = self._phir(tau, delta) - propiedades = {} - propiedades["fir"] = res.fi - propiedades["fird"] = res.fid - propiedades["firdd"] = res.fidd - propiedades["delta"] = delta - - propiedades["rho"] = rho - propiedades["P"] = (1+delta*res.fid)*self.R*T*rho - propiedades["h"] = self.R*T*(1+tau*(ideal.fit+res.fit)+delta*res.fid) - propiedades["s"] = self.R*(tau*(ideal.fit+res.fit)-ideal.fi-res.fi) - propiedades["cv"] = -self.R*tau**2*(ideal.fitt+res.fitt) - propiedades["alfap"] = (1-delta*tau*res.fidt/(1+delta*res.fid))/T - propiedades["betap"] = rho*( - 1+(delta*res.fid+delta**2*res.fidd)/(1+delta*res.fid)) - return propiedades + P = (1+delta*res.fid)*self.R*T*rho + h = self.R*T*(1+tau*(ideal.fit+res.fit)+delta*res.fid) + s = self.R*(tau*(ideal.fit+res.fit)-ideal.fi-res.fi) + cv = -self.R*tau**2*(ideal.fitt+res.fitt) + alfap = (1-delta*tau*res.fidt/(1+delta*res.fid))/T + betap = rho*(1+(delta*res.fid+delta**2*res.fidd)/(1+delta*res.fid)) + return MEoSProperties(rho, P, h, s, cv, alfap, betap, + res.fi, res.fid, res.fidd, delta) def _prop0(self, rho: float, T: float) -> _fase: """Ideal gas properties""" @@ -2671,14 +2671,14 @@ def _visco(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: ref = IAPWS95() st = ref._Helmholtz(rho, 1.5*Tc) delta = rho/rhoc - drho = 1e3/self.R/1.5/Tc/(1+2*delta*st["fird"]+delta**2*st["firdd"]) + drho = 1e3/self.R/1.5/Tc/(1+2*delta*st.fird+delta**2*st.firdd) return _Viscosity(rho, T, fase, drho) def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: ref = IAPWS95() st = ref._Helmholtz(rho, 1.5*Tc) delta = rho/rhoc - drho = 1e3/self.R/1.5/Tc/(1+2*delta*st["fird"]+delta**2*st["firdd"]) + drho = 1e3/self.R/1.5/Tc/(1+2*delta*st.fird+delta**2*st.firdd) return _ThCond(rho, T, fase, drho) def _surface(self, T: float) -> float: diff --git a/test.py b/test.py index 3d874d4..ac35d9f 100755 --- a/test.py +++ b/test.py @@ -152,10 +152,10 @@ def test_saturation(self) -> None: self.assertEqual(round(Ps, 9), 0.698451167) self.assertEqual(round(rhol, 6), 999.887406) self.assertEqual(round(rhov, 11), 0.00550664919) - self.assertEqual(round(liquid["h"], 8), 7.75972202) - self.assertEqual(round(vapor["h"], 5), 2504.28995) - self.assertEqual(round(liquid["s"], 10), 0.0283094670) - self.assertEqual(round(vapor["s"], 8), 9.10660121) + self.assertEqual(round(liquid.h, 8), 7.75972202) + self.assertEqual(round(vapor.h, 5), 2504.28995) + self.assertEqual(round(liquid.s, 10), 0.0283094670) + self.assertEqual(round(vapor.s, 8), 9.10660121) rhol, rhov, Ps = fluid._saturation(450) liquid = fluid._Helmholtz(rhol, 450) @@ -163,10 +163,10 @@ def test_saturation(self) -> None: self.assertEqual(round(Ps, 6), 932.203564) self.assertEqual(round(rhol, 6), 890.341250) self.assertEqual(round(rhov, 8), 4.81200360) - self.assertEqual(round(liquid["h"], 6), 749.161585) - self.assertEqual(round(vapor["h"], 5), 2774.41078) - self.assertEqual(round(liquid["s"], 8), 2.10865845) - self.assertEqual(round(vapor["s"], 8), 6.60921221) + self.assertEqual(round(liquid.h, 6), 749.161585) + self.assertEqual(round(vapor.h, 5), 2774.41078) + self.assertEqual(round(liquid.s, 8), 2.10865845) + self.assertEqual(round(vapor.s, 8), 6.60921221) rhol, rhov, Ps = fluid._saturation(625) liquid = fluid._Helmholtz(rhol, 625) @@ -174,10 +174,10 @@ def test_saturation(self) -> None: self.assertEqual(round(Ps, 4), 16908.2693) self.assertEqual(round(rhol, 6), 567.090385) self.assertEqual(round(rhov, 6), 118.290280) - self.assertEqual(round(liquid["h"], 5), 1686.26976) - self.assertEqual(round(vapor["h"], 5), 2550.71625) - self.assertEqual(round(liquid["s"], 8), 3.80194683) - self.assertEqual(round(vapor["s"], 8), 5.18506121) + self.assertEqual(round(liquid.h, 5), 1686.26976) + self.assertEqual(round(vapor.h, 5), 2550.71625) + self.assertEqual(round(liquid.s, 8), 3.80194683) + self.assertEqual(round(vapor.s, 8), 5.18506121) def test_LowT(self) -> None: """Table 3, pag 5""" From 6337fcf63e2d58285c830a5e181db71a9af8fab6 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Fri, 19 Mar 2021 02:03:41 -0400 Subject: [PATCH 092/102] Why so much complexity for constants? Maybe I'm still missing something here, but there seems to be a lots of fancy for what appears to be a pair of constants. There's still the self.rhoc and self.Tc variants, but they seem to be constants as well. Hopefully this hasn't broken anything... --- iapws/ammonia.py | 4 +++- iapws/humidAir.py | 4 ++-- iapws/iapws95.py | 27 ++++++++++++++++----------- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/iapws/ammonia.py b/iapws/ammonia.py index 055ee5c..9b7b983 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -37,7 +37,7 @@ class NH3(MEoS): CASNumber = "7664-41-7" formula = "NH3" synonym = "R-717" - rhoc = 225. + rhoc = 225.0 Tc = 405.40 Pc = 11.333 # MPa M = 17.03026 # g/mol @@ -53,6 +53,8 @@ class NH3(MEoS): "ao_hyp": [], "hyp": []} _constant_R = 8.314471 + _constant_rhoc = 225.0 + _constant_Tref = 405.40 _constants = { "nr1": [-0.1858814e01, 0.4554431e-1, 0.7238548, 0.1229470e-1, 0.2141882e-10], diff --git a/iapws/humidAir.py b/iapws/humidAir.py index 1f86691..8585495 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -300,9 +300,9 @@ class Air(MEoSBlend): } _constant_R = 8.31451 + _constant_rhoc = 10.4477*Ma + _constant_Tref = 132.6312 _constants = { - "Tref": [132.6312], "rhoref": [10.4477*Ma], - "nr1": [0.118160747229, 0.713116392079, -0.161824192067e1, 0.714140178971e-1, -0.865421396646e-1, 0.134211176704, 0.112626704218e-1, -0.420533228842e-1, 0.349008431982e-1, diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 1de7305..f7e503f 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -587,8 +587,8 @@ def calculo(self) -> None: rhoo = 900 self.R = self._constant_R/self.M - rhoc = self._constants.get("rhoref", [self.rhoc])[0] - Tc = self._constants.get("Tref", [self.Tc])[0] + rhoc = self._constant_rhoc + Tc = self._constant_Tref if self._mode not in ("Tx", "Px"): # Method with iteration necessary to get x @@ -1640,8 +1640,8 @@ def derivative(self, z: str, x: str, y: str, fase: _fase) -> float: def _saturation(self, T: float) -> Tuple[float, float, float]: """Saturation calculation for two phase search""" - rhoc = self._constants.get("rhoref", [self.rhoc])[0] - Tc = self._constants.get("Tref", [self.Tc])[0] + rhoc = self._constant_rhoc + Tc = self._constant_Tref if T > Tc: T = Tc @@ -1712,8 +1712,8 @@ def _Helmholtz(self, rho: float, T: float) -> MEoSProperties: rho = 1e-20 if T < 50: T = 50 - rhoc = self._constants.get("rhoref", [self.rhoc])[0] - Tc = self._constants.get("Tref", [self.Tc])[0] + rhoc = self._constant_rhoc + Tc = self._constant_Tref delta = rho/rhoc tau = Tc/T ideal = self._phi0(tau, delta) @@ -1731,8 +1731,9 @@ def _Helmholtz(self, rho: float, T: float) -> MEoSProperties: def _prop0(self, rho: float, T: float) -> _fase: """Ideal gas properties""" - rhoc = self._constants.get("rhoref", [self.rhoc])[0] - Tc = self._constants.get("Tref", [self.Tc])[0] + rhoc = self._constant_rhoc + Tc = self._constant_Tref + delta = rho/rhoc tau = Tc/T ideal = self._phi0(tau, delta) @@ -1975,7 +1976,7 @@ def _virial(self, T: float) -> Dict[str, float]: * B: ∂fir/∂δ|δ->0 * C: ∂²fir/∂δ²|δ->0 """ - Tc = self._constants.get("Tref", [self.Tc])[0] + Tc = self._constant_Tref tau = Tc/T B = C = 0.0 delta = 1e-200 @@ -2080,8 +2081,8 @@ def _derivDimensional(self, rho: float, T: float) -> HelmholtzDerivatives: if not rho: return HelmholtzDerivatives(0.0, 0.0, 0.0, 0.0, 0.0, 0.0) - rhoc = self._constants.get("rhoref", [self.rhoc])[0] - Tc = self._constants.get("Tref", [self.Tc])[0] + rhoc = self._constant_rhoc + Tc = self._constant_Tref delta = rho/rhoc tau = Tc/T @@ -2411,6 +2412,8 @@ class IAPWS95(MEoS): 27.5075105]} _constant_R = 8.314371357587 + _constant_rhoc = rhoc + _constant_Tref = Tc _constants = { "nr1": [0.12533547935523e-1, 0.78957634722828e1, -0.87803203303561e1, 0.31802509345418, -0.26145533859358, -0.78199751687981e-2, @@ -2761,6 +2764,8 @@ class D2O(MEoS): "ao_hyp": [], "hyp": []} _constant_R = 8.3144598 + _constant_rhoc = rhoc_D2O + _constant_Tref = Tc_D2O _constants = { "nr1": [0.122082060e-1, 0.296956870e1, -0.379004540e1, 0.941089600, -0.922466250, -0.139604190e-1], From 16bff347878a47268d87c92164d3945d6f303799 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Fri, 19 Mar 2021 02:22:22 -0400 Subject: [PATCH 093/102] Yet more evidence that rhoc and Tc are basically just constants? The object properties are apparently never assigned to except during initialization, where they're set to match the global constant, which is typically imported from _iapws but is sometimes defined in the module with a different value? --- iapws/ammonia.py | 2 +- iapws/iapws95.py | 95 +++++++++++++++++++++++++----------------------- iapws/iapws97.py | 11 +++--- 3 files changed, 56 insertions(+), 52 deletions(-) diff --git a/iapws/ammonia.py b/iapws/ammonia.py index 9b7b983..4ec67a0 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -172,7 +172,7 @@ def _thermo(self, rho: float, T: float, fase: Optional[_fase] = None) -> float: # The paper use a diferent rhoc value to the EoS rhoc = 235 - if rho == rhoc and T == self.Tc: + if rho == rhoc and T == self._constant_Tref: warnings.warn("Thermal conductiviy undefined in critical point") return float('nan') diff --git a/iapws/iapws95.py b/iapws/iapws95.py index f7e503f..a382d94 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -420,6 +420,9 @@ class MEoS(_fase): # Defined in derived classes NH3 and Air. _surf: Dict[str, List[float]] Fi0: Dict[str, List[float]] + # Defined by derived classes + _constant_rhoc: float + _constant_Tref: float kwargs = {"T": 0.0, "P": 0.0, @@ -471,7 +474,7 @@ def __init__(self, **kwargs): self.Svap: Optional[float] = None self.R = self.__class__._constant_R/self.M - self.Zc = self.Pc/self.rhoc/self.R/self.Tc + self.Zc = self.Pc/self._constant_rhoc/self.R/self._constant_Tref self.kwargs = MEoS.kwargs.copy() self.__call__(**kwargs) @@ -601,13 +604,13 @@ def calculo(self) -> None: except NotImplementedError: if rho0: rhoo = rho0 - elif T < self.Tc and P < self.Pc and \ + elif T < self._constant_Tref and P < self.Pc and \ self._Vapor_Pressure(T) < P: rhoo = self._Liquid_Density(T) - elif T < self.Tc and P < self.Pc: + elif T < self._constant_Tref and P < self.Pc: rhoo = self._Vapor_Density(T) else: - rhoo = self.rhoc*3 + rhoo = self._constant_rhoc*3 def rho_func(rho: float) -> float: delta = rho/rhoc @@ -620,7 +623,7 @@ def rho_func(rho: float) -> float: rho = float(fsolve(rho_func, rhoo)[0]) # Calculate quality - if T > self.Tc: + if T > self._constant_Tref: x = 1 else: Ps = self._Vapor_Pressure(T) @@ -645,8 +648,8 @@ def rho_func(rho: float) -> float: ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return ho-h - if T >= self.Tc: - rhoo = self.rhoc + if T >= self._constant_Tref: + rhoo = self._constant_rhoc rho = float(fsolve(rho_func, rhoo)[0]) else: x0 = self.kwargs["x0"] @@ -691,8 +694,8 @@ def rho_func(rho: float) -> float: so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) return so-s - if T >= self.Tc: - rhoo = self.rhoc + if T >= self._constant_Tref: + rhoo = self._constant_rhoc rho = float(fsolve(rho_func, rhoo)[0]) else: rhov = self._Vapor_Density(T) @@ -740,8 +743,8 @@ def rho_func(rho: float) -> float: return ho-Po/rho-u - if T >= self.Tc: - rhoo = self.rhoc + if T >= self._constant_Tref: + rhoo = self._constant_rhoc rho = float(fsolve(rho_func, rhoo)[0]) else: rhov = self._Vapor_Density(T) @@ -794,8 +797,8 @@ def t_func(T: float) -> float: def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: T, rhol, rhog = parr tau = Tc/T - deltaL = rhol/self.rhoc - deltaG = rhog/self.rhoc + deltaL = rhol/self._constant_rhoc + deltaG = rhog/self._constant_rhoc firL = _phir(tau, deltaL, self._constants) firdL = _phird(tau, deltaL, self._constants) @@ -852,8 +855,8 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ float, float, float, float]: T, rhol, rhog, x = parr tau = Tc/T - deltaL = rhol/self.rhoc - deltaG = rhog/self.rhoc + deltaL = rhol/self._constant_rhoc + deltaG = rhog/self._constant_rhoc ideal = self._phi0(tau, deltaL) @@ -954,8 +957,8 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ float, float, float, float]: T, rhol, rhog, x = parr tau = Tc/T - deltaL = rhol/self.rhoc - deltaG = rhog/self.rhoc + deltaL = rhol/self._constant_rhoc + deltaG = rhog/self._constant_rhoc ideal = self._phi0(tau, deltaL) @@ -1017,8 +1020,8 @@ def t_func(T: float) -> float: def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: T, rhol, rhog = parr tau = Tc/T - deltaL = rhol/self.rhoc - deltaG = rhog/self.rhoc + deltaL = rhol/self._constant_rhoc + deltaG = rhog/self._constant_rhoc ideal = self._phi0(tau, deltaL) firL = _phir(tau, deltaL, self._constants) @@ -1078,8 +1081,8 @@ def t_func(T: float) -> float: def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: T, rhol, rhog = parr tau = Tc/T - deltaL = rhol/self.rhoc - deltaG = rhog/self.rhoc + deltaL = rhol/self._constant_rhoc + deltaG = rhog/self._constant_rhoc idealL = self._phi0(tau, deltaL) idealG = self._phi0(tau, deltaG) @@ -1142,8 +1145,8 @@ def t_func(T: float) -> float: def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: T, rhol, rhog = parr tau = Tc/T - deltaL = rhol/self.rhoc - deltaG = rhog/self.rhoc + deltaL = rhol/self._constant_rhoc + deltaG = rhog/self._constant_rhoc ideal = self._phi0(tau, deltaL) firL = _phir(tau, deltaL, self._constants) @@ -1210,8 +1213,8 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ float, float, float, float]: T, rhol, rhog, x = parr tau = Tc/T - deltaL = rhol/self.rhoc - deltaG = rhog/self.rhoc + deltaL = rhol/self._constant_rhoc + deltaG = rhog/self._constant_rhoc idealL = self._phi0(tau, deltaL) idealG = self._phi0(tau, deltaG) @@ -1276,8 +1279,8 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ float, float, float, float]: T, rhol, rhog, x = parr tau = Tc/T - deltaL = rhol/self.rhoc - deltaG = rhog/self.rhoc + deltaL = rhol/self._constant_rhoc + deltaG = rhog/self._constant_rhoc ideal = self._phi0(tau, deltaL) @@ -1345,8 +1348,8 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ float, float, float, float]: T, rhol, rhog, x = parr tau = Tc/T - deltaL = rhol/self.rhoc - deltaG = rhog/self.rhoc + deltaL = rhol/self._constant_rhoc + deltaG = rhog/self._constant_rhoc idealL = self._phi0(tau, deltaL) idealG = self._phi0(tau, deltaG) @@ -1395,7 +1398,7 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 elif self._mode == "Trho": - if T < self.Tc: + if T < self._constant_Tref: rhov = self._Vapor_Density(T) rhol = self._Liquid_Density(T) if rhol > rho > rhov: @@ -1410,7 +1413,7 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ T = float(T) propiedades = self._Helmholtz(rho, T) - if T > self.Tc: + if T > self._constant_Tref: x = 1 elif x is None: x = 0 @@ -1420,7 +1423,7 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ elif self._mode == "Tx": # Check input T in saturation range - if self.Tt > T or self.Tc < T or x > 1 or x < 0: + if self.Tt > T or self._constant_Tref < T or x > 1 or x < 0: raise NotImplementedError("Incoming out of bound") rhol, rhov, Ps = self._saturation(T) @@ -1442,8 +1445,8 @@ def t_func(T: float) -> float: rhol = self._Liquid_Density(T) rhog = self._Vapor_Density(T) - deltaL = rhol/self.rhoc - deltaG = rhog/self.rhoc + deltaL = rhol/self._constant_rhoc + deltaG = rhog/self._constant_rhoc tau = Tc/T @@ -1458,7 +1461,7 @@ def t_func(T: float) -> float: elif self.name == "water": To = _TSat_P(P) else: - To = (self.Tc+self.Tt)/2 + To = (self._constant_Tref+self.Tt)/2 T = float(fsolve(t_func, To)[0]) rhol, rhov, Ps = self._saturation(T) vapor = self._Helmholtz(rhov, T) @@ -1469,7 +1472,7 @@ def t_func(T: float) -> float: propiedades = vapor self.T = T - self.Tr = T/self.Tc + self.Tr = T/self._constant_Tref self.P = P self.Pr = self.P/self.Pc self.x = x @@ -1477,7 +1480,7 @@ def t_func(T: float) -> float: region = 4 else: region = 0 - self.phase = getphase(self.Tc, self.Pc, self.T, self.P, self.x, region) + self.phase = getphase(self._constant_Tref, self.Pc, self.T, self.P, self.x, region) self.Liquid = _fase() self.Gas = _fase() @@ -1509,14 +1512,14 @@ def t_func(T: float) -> float: self.IntP = x*self.Gas.IntP+(1-x)*self.Liquid.IntP # Calculate special properties useful only for one phase - if self._mode in ("Px", "Tx") or (x < 1 and self.Tt <= T <= self.Tc): + if self._mode in ("Px", "Tx") or (x < 1 and self.Tt <= T <= self._constant_Tref): self.sigma = self._surface(T) else: self.sigma = None vir = self._virial(T) - self.virialB = vir["B"]/self.rhoc - self.virialC = vir["C"]/self.rhoc**2 + self.virialB = vir["B"]/self._constant_rhoc + self.virialC = vir["C"]/self._constant_rhoc**2 if 0 < x < 1: self.Hvap = vapor.h-liquido.h @@ -1668,8 +1671,8 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: if rhoL == rhoG: Ps = self.Pc else: - deltaL = rhoL/self.rhoc - deltaG = rhoG/self.rhoc + deltaL = rhoL/self._constant_rhoc + deltaG = rhoG/self._constant_rhoc firL = _phir(tau, deltaL, self._constants) firG = _phir(tau, deltaG, self._constants) @@ -2119,7 +2122,7 @@ def _surface(self, T: float) -> float: sigma: coefficient exp: exponent """ - tau = 1-T/self.Tc + tau = 1-T/self._constant_Tref sigma = 0.0 for n, t in zip(self._surf["sigma"], self._surf["exp"]): sigma += n*tau**t @@ -2483,7 +2486,7 @@ def _phi0(self, tau: float, delta: float) -> HelmholtzDerivatives: """Low temperature extension of the IAPWS-95""" prop = MEoS._phi0(self, tau, delta) - T = self.Tc/tau + T = self._constant_Tref/tau if 50 <= T < 130: fex, fext, fextt = self._phiex(T) prop.fi += fex @@ -2493,9 +2496,9 @@ def _phi0(self, tau: float, delta: float) -> HelmholtzDerivatives: def _phiex(self, T: float) -> Tuple[float, float, float]: """Low temperature extension""" - tau = self.Tc/T + tau = self._constant_Tref/T E = 0.278296458178592 - ep = self.Tc/130 + ep = self._constant_Tref/130 fex = E*(-1/2/tau-3/ep**2*(tau+ep)*log(tau/ep)-9/2/ep+9*tau/2/ep**2 + tau**2/2/ep**3) fext = E*(1/2/tau**2-3/tau/ep-3/ep**2*log(tau/ep)+3/2/ep**2+tau/ep**3) diff --git a/iapws/iapws97.py b/iapws/iapws97.py index 3c75565..d96f020 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -4323,6 +4323,9 @@ class IAPWS97(_fase): status = 0 msg = "Unknown variables" + _constant_rhoc = rhoc + _constant_Tref = Tc + def __init__(self, **kwargs): super().__init__() self.v0: Optional[float] = None @@ -4615,8 +4618,6 @@ def rho_funcion(rho: float) -> float: self.M = 18.015257 # kg/kmol self.Pc = Pc - self.Tc = Tc - self.rhoc = rhoc self.Tt = Tt self.Tb = Tb self.f_accent = f_acent @@ -4632,9 +4633,9 @@ def rho_funcion(rho: float) -> float: self.P = propiedades.P self.v = propiedades.v self.rho = 1/self.v - self.phase = getphase(self.Tc, self.Pc, self.T, self.P, self.x, - self.region) - self.Tr = self.T/self.Tc + self.phase = getphase(self._constant_Tref, self.Pc, self.T, + self.P, self.x, self.region) + self.Tr = self.T/self._constant_Tref self.Pr = self.P/self.Pc # Ideal properties From f8a556a4012644c6222efdad95841331167c589a Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Fri, 19 Mar 2021 21:00:43 -0400 Subject: [PATCH 094/102] Move the constants and _phir methods into a new class. This approach make it clear how the remaining constants are scoped to a specific set of functions. The constants do not change and how the "missing" contants are handled. I also think the data flow from the constants to where they're used is a lot more straightforward. --- iapws/ammonia.py | 38 +- iapws/humidAir.py | 40 +- iapws/iapws95.py | 1214 +++++++++++++++++++++------------------------ test.py | 6 +- 4 files changed, 618 insertions(+), 680 deletions(-) diff --git a/iapws/ammonia.py b/iapws/ammonia.py index 4ec67a0..8c7b578 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -16,7 +16,7 @@ from typing import Dict, Optional from scipy.constants import Boltzmann -from .iapws95 import MEoS, IAPWS95, mainClassDoc +from .iapws95 import MEoS, IAPWS95, mainClassDoc, ResidualContribution from ._utils import _fase @@ -55,20 +55,24 @@ class NH3(MEoS): _constant_R = 8.314471 _constant_rhoc = 225.0 _constant_Tref = 405.40 - _constants = { - "nr1": [-0.1858814e01, 0.4554431e-1, 0.7238548, 0.1229470e-1, - 0.2141882e-10], - "d1": [1, 2, 1, 4, 15], - "t1": [1.5, -0.5, 0.5, 1., 3.], - - "nr2": [-0.1430020e-1, 0.3441324, -0.2873571, 0.2352589e-4, - -0.3497111e-1, 0.1831117e-2, 0.2397852e-1, -0.4085375e-1, - 0.2379275, -0.3548972e-1, -0.1823729, 0.2281556e-1, - -0.6663444e-2, -0.8847486e-2, 0.2272635e-2, -0.5588655e-3], - "d2": [3, 3, 1, 8, 2, 8, 1, 1, 2, 3, 2, 4, 3, 1, 2, 4], - "t2": [0, 3, 4, 4, 5, 5, 3, 6, 8, 8, 10, 10, 5, 7.5, 15, 30], - "c2": [1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3], - "gamma2": [1]*16} + residual = ResidualContribution( + nr1=[-0.1858814e01, 0.4554431e-1, 0.7238548, 0.1229470e-1, + 0.2141882e-10], + d1=[1, 2, 1, 4, 15], + t1=[1.5, -0.5, 0.5, 1., 3.], + + nr2=[-0.1430020e-1, 0.3441324, -0.2873571, 0.2352589e-4, + -0.3497111e-1, 0.1831117e-2, 0.2397852e-1, -0.4085375e-1, + 0.2379275, -0.3548972e-1, -0.1823729, 0.2281556e-1, + -0.6663444e-2, -0.8847486e-2, 0.2272635e-2, -0.5588655e-3], + d2=[3, 3, 1, 8, 2, 8, 1, 1, 2, 3, 2, 4, 3, 1, 2, 4], + t2=[0, 3, 4, 4, 5, 5, 3, 6, 8, 8, 10, 10, 5, 7.5, 15, 30], + c2=[1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3], + gamma2=[1]*16, + + nr3=[], d3=[], t3=[], alfa3=[], beta3=[], gamma3=[], epsilon3=[], + nr4=[], a4=[], b4=[], A=[], B=[], C=[], D=[], beta4=[], + ) _melting = {"eq": 1, "Tref": Tt, "Pref": 1000, "Tmin": Tt, "Tmax": 700.0, @@ -441,10 +445,10 @@ def _phir(self, rho: float, T: float, x: float) -> Dict[str, float]: delta = rho/rhon water = IAPWS95() - phi1 = water._phir(tau, delta) + phi1 = water.residual.helmholtz(tau, delta) ammonia = NH3() - phi2 = ammonia._phir(tau, delta) + phi2 = ammonia.residual.helmholtz(tau, delta) Dphi = self._Dphir(tau, delta, x) diff --git a/iapws/humidAir.py b/iapws/humidAir.py index 8585495..ff4b866 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -23,7 +23,7 @@ from ._iapws import _global_M from ._iapws import _Ice from ._utils import _fase, deriv_G -from .iapws95 import MEoS, IAPWS95, mainClassDoc +from .iapws95 import MEoS, IAPWS95, mainClassDoc, ResidualContribution Ma = 28.96546 # g/mol @@ -106,7 +106,7 @@ def _virial(T: float) -> Dict[str, float]: # The paper use the specific formulation of virial, here using the general # formulation from helmholtz mEoS wt = IAPWS95() - vir = wt._virial(T) + vir = wt.residual._virial(T, wt._constant_Tref) Bww = vir["B"]/wt.rhoc*wt.M Cwww = vir["C"]/wt.rhoc**2*wt.M**2 @@ -141,7 +141,7 @@ def _virial(T: float) -> Dict[str, float]: # Virial coefficient for air, using too the general virial procedure air = Air() - vir = air._virial(T) + vir = air.residual._virial(T, air._constant_Tref) Baa = vir["B"]/air.rhoc*air.M Caaa = vir["C"]/air.rhoc**2*air.M**2 @@ -302,21 +302,25 @@ class Air(MEoSBlend): _constant_R = 8.31451 _constant_rhoc = 10.4477*Ma _constant_Tref = 132.6312 - _constants = { - "nr1": [0.118160747229, 0.713116392079, -0.161824192067e1, - 0.714140178971e-1, -0.865421396646e-1, 0.134211176704, - 0.112626704218e-1, -0.420533228842e-1, 0.349008431982e-1, - 0.164957183186e-3], - "d1": [1, 1, 1, 2, 3, 3, 4, 4, 4, 6], - "t1": [0, 0.33, 1.01, 0, 0, 0.15, 0, 0.2, 0.35, 1.35], - - "nr2": [-0.101365037912, -0.173813690970, -0.472103183731e-1, - -0.122523554253e-1, -0.146629609713, -0.316055879821e-1, - 0.233594806142e-3, 0.148287891978e-1, -0.938782884667e-2], - "d2": [1, 3, 5, 6, 1, 3, 11, 1, 3], - "t2": [1.6, 0.8, 0.95, 1.25, 3.6, 6, 3.25, 3.5, 15], - "c2": [1, 1, 1, 1, 2, 2, 2, 3, 3], - "gamma2": [1]*9} + residual = ResidualContribution( + nr1=[0.118160747229, 0.713116392079, -0.161824192067e1, + 0.714140178971e-1, -0.865421396646e-1, 0.134211176704, + 0.112626704218e-1, -0.420533228842e-1, 0.349008431982e-1, + 0.164957183186e-3], + d1=[1, 1, 1, 2, 3, 3, 4, 4, 4, 6], + t1=[0, 0.33, 1.01, 0, 0, 0.15, 0, 0.2, 0.35, 1.35], + + nr2=[-0.101365037912, -0.173813690970, -0.472103183731e-1, + -0.122523554253e-1, -0.146629609713, -0.316055879821e-1, + 0.233594806142e-3, 0.148287891978e-1, -0.938782884667e-2], + d2=[1, 3, 5, 6, 1, 3, 11, 1, 3], + t2=[1.6, 0.8, 0.95, 1.25, 3.6, 6, 3.25, 3.5, 15], + c2=[1, 1, 1, 1, 2, 2, 2, 3, 3], + gamma2=[1]*9, + + nr3=[], d3=[], t3=[], alfa3=[], beta3=[], gamma3=[], epsilon3=[], + nr4=[], a4=[], b4=[], A=[], B=[], C=[], D=[], beta4=[], + ) _blend = { "Tj": 132.6312, "Pj": 3.78502, diff --git a/iapws/iapws95.py b/iapws/iapws95.py index a382d94..f1b5dd1 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -25,248 +25,401 @@ from ._utils import _fase, getphase, deriv_H, HelmholtzDerivatives -def _phir(tau: float, delta: float, coef: Dict[str, List[float]]) -> float: - """Residual contribution to the adimensional free Helmholtz energy +class ResidualContribution(object): + """Residual contribution to the adimensional free Helmholtz energy""" + + def __init__(self, nr1: List[float], d1: List[float], t1: List[float], + nr2: List[float], d2: List[float], gamma2: List[int], + t2: List[float], c2: List[int], nr3: List[float], + d3: List[int], t3: List[float], alfa3: List[float], + epsilon3: List[float], beta3: List[float], gamma3: List[float], + nr4: List[float], a4: List[float], b4: List[float], + A: List[float], B: List[float], C: List[int], + D: List[int], beta4: List[float]) -> None: + # Polinomial terms + self.nr1 = nr1 + self.d1 = d1 + self.t1 = t1 + # Exponential terms + self.nr2 = nr2 + self.d2 = d2 + self.gamma2 = gamma2 # Gamma2 is always ones? + self.t2 = t2 + self.c2 = c2 + # Gaussian terms (optional, may be empty lists) + self.nr3 = nr3 + self.d3 = d3 + self.t3 = t3 + self.alfa3 = alfa3 + self.epsilon3 = epsilon3 + self.beta3 = beta3 + self.gamma3 = gamma3 + # Non analitic terms (optional, may be empty lists) + self.nr4 = nr4 + self.a4 = a4 + self.b4 = b4 + self.A = A + self.B = B + self.C = C + self.D = D + self.beta4 = beta4 + + def phir(self, tau: float, delta: float) -> float: + """Residual contribution to the adimensional free Helmholtz energy - Parameters - ---------- - tau : float - Inverse reduced temperature Tc/T, [-] - delta : float - Reduced density rho/rhoc, [-] - coef : dict - Dictionary with equation of state parameters - - Returns - ------- - fir : float - Adimensional free Helmholtz energy + Parameters + ---------- + tau : float + Inverse reduced temperature Tc/T, [-] + delta : float + Reduced density rho/rhoc, [-] + coef : dict + Dictionary with equation of state parameters - References - ---------- - IAPWS, Revised Release on the IAPWS Formulation 1995 for the - Thermodynamic Properties of Ordinary Water Substance for General and - Scientific Use, September 2016, Table 5 - http://www.iapws.org/relguide/IAPWS-95.html - """ - fir = 0.0 - - # Convert numpy.Float64 back into Python floats. - tau = float(tau) - delta = float(delta) - - # Polinomial terms - nr1 = coef.get("nr1", []) - d1 = coef.get("d1", []) - t1 = coef.get("t1", []) - for n, d, t in zip(nr1, d1, t1): - fir += n*delta**d*tau**t - - # Exponential terms - nr2 = coef.get("nr2", []) - d2 = coef.get("d2", []) - g2 = coef.get("gamma2", []) - t2 = coef.get("t2", []) - c2 = coef.get("c2", []) - for n, d, g, t, c in zip(nr2, d2, g2, t2, c2): - fir += n*delta**d*tau**t*exp(-g*delta**c) - - # Gaussian terms - nr3 = coef.get("nr3", []) - d3 = coef.get("d3", []) - t3 = coef.get("t3", []) - a3 = coef.get("alfa3", []) - e3 = coef.get("epsilon3", []) - b3 = coef.get("beta3", []) - g3 = coef.get("gamma3", []) - for n, d, t, a, e, b, g in zip(nr3, d3, t3, a3, e3, b3, g3): - fir += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2) - - # Non analitic terms - nr4 = coef.get("nr4", []) - a4 = coef.get("a4", []) - b4 = coef.get("b4", []) - Ai = coef.get("A", []) - Bi = coef.get("B", []) - Ci = coef.get("C", []) - Di = coef.get("D", []) - bt4 = coef.get("beta4", []) - for n, a, b, A, B, C, D, bt in zip(nr4, a4, b4, Ai, Bi, Ci, Di, bt4): - Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) - F = exp(-C*(delta-1)**2-D*(tau-1)**2) - Delta = Tita**2+B*((delta-1)**2)**a - fir += n*Delta**b*delta*F - - return fir - - -def _phird(tau: float, delta: float, coef: Dict[str, List[float]]) -> float: - r"""Residual contribution to the adimensional free Helmholtz energy, delta - derivative + Returns + ------- + fir : float + Adimensional free Helmholtz energy - Parameters - ---------- - tau : float - Inverse reduced temperature Tc/T, [-] - delta : float - Reduced density rho/rhoc, [-] - coef : dict - Dictionary with equation of state parameters - - Returns - ------- - fird : float - .. math:: - \left.\frac{\partial \phi^r_{\delta}}{\partial \delta}\right|_{\tau} + References + ---------- + IAPWS, Revised Release on the IAPWS Formulation 1995 for the + Thermodynamic Properties of Ordinary Water Substance for General and + Scientific Use, September 2016, Table 5 + http://www.iapws.org/relguide/IAPWS-95.html + """ + # Ensure parameters are really floats. + tau = float(tau) + delta = float(delta) - References - ---------- - IAPWS, Revised Release on the IAPWS Formulation 1995 for the - Thermodynamic Properties of Ordinary Water Substance for General and - Scientific Use, September 2016, Table 5 - http://www.iapws.org/relguide/IAPWS-95.html - """ - fird = 0.0 - - # Convert numpy.Float64 back into Python floats. - tau = float(tau) - delta = float(delta) - - # Polinomial terms - nr1 = coef.get("nr1", []) - d1 = coef.get("d1", []) - t1 = coef.get("t1", []) - for n, d, t in zip(nr1, d1, t1): - fird += n*d*delta**(d-1)*tau**t - - # Exponential terms - nr2 = coef.get("nr2", []) - d2 = coef.get("d2", []) - g2 = coef.get("gamma2", []) - t2 = coef.get("t2", []) - c2 = coef.get("c2", []) - for n, d, g, t, c in zip(nr2, d2, g2, t2, c2): - try: - expt = exp(-g*delta**c) - except OverflowError: - fird = float('nan') - break - fird += n*expt*delta**(d-1)*tau**t*(d-g*c*delta**c) - - # Gaussian terms - nr3 = coef.get("nr3", []) - d3 = coef.get("d3", []) - t3 = coef.get("t3", []) - a3 = coef.get("alfa3", []) - e3 = coef.get("epsilon3", []) - b3 = coef.get("beta3", []) - g3 = coef.get("gamma3", []) - for n, d, t, a, e, b, g in zip(nr3, d3, t3, a3, e3, b3, g3): - expt = exp(-a*(delta-e)**2-b*(tau-g)**2) - fird += n*delta**d*tau**t*expt*(d/delta-2*a*(delta-e)) - - # Non analitic terms - nr4 = coef.get("nr4", []) - a4 = coef.get("a4", []) - b4 = coef.get("b4", []) - Ai = coef.get("A", []) - Bi = coef.get("B", []) - Ci = coef.get("C", []) - Di = coef.get("D", []) - bt4 = coef.get("beta4", []) - for n, a, b, A, B, C, D, bt in zip(nr4, a4, b4, Ai, Bi, Ci, Di, bt4): - Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) - F = exp(-C*(delta-1)**2-D*(tau-1)**2) - Fd = -2*C*F*(delta-1) - - Delta = Tita**2+B*((delta-1)**2)**a - Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**(0.5/bt-1) - + 2*B*a*((delta-1)**2)**(a-1)) - DeltaBd = b*Delta**(b-1)*Deltad - - fird += n*(Delta**b*(F+delta*Fd)+DeltaBd*delta*F) - - return fird - - -def _phirt(tau: float, delta: float, coef: Dict[str, List[float]]) -> float: - r"""Residual contribution to the adimensional free Helmholtz energy, tau - derivative + fir = 0.0 + # Polinomial terms + for n, d, t in zip(self.nr1, self.d1, self.t1): + fir += n*delta**d*tau**t - Parameters - ---------- - tau : float - Inverse reduced temperature Tc/T, [-] - delta : float - Reduced density rho/rhoc, [-] - coef : dict - Dictionary with equation of state parameters - - Returns - ------- - firt : float - .. math:: - \left.\frac{\partial \phi^r_{\tau}}{\partial \tau}\right|_{\delta} + # Exponential terms + for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): + fir += n*delta**d*tau**t*exp(-g*delta**c) - References - ---------- - IAPWS, Revised Release on the IAPWS Formulation 1995 for the - Thermodynamic Properties of Ordinary Water Substance for General and - Scientific Use, September 2016, Table 5 - http://www.iapws.org/relguide/IAPWS-95.html - """ - firt = 0.0 - - # Convert numpy.Float64 back into Python floats. - tau = float(tau) - delta = float(delta) - - # Polinomial terms - nr1 = coef.get("nr1", []) - d1 = coef.get("d1", []) - t1 = coef.get("t1", []) - for n, d, t in zip(nr1, d1, t1): - firt += n*t*delta**d*tau**(t-1) - - # Exponential terms - nr2 = coef.get("nr2", []) - d2 = coef.get("d2", []) - g2 = coef.get("gamma2", []) - t2 = coef.get("t2", []) - c2 = coef.get("c2", []) - for n, d, g, t, c in zip(nr2, d2, g2, t2, c2): - firt += n*t*delta**d*tau**(t-1)*exp(-g*delta**c) - - # Gaussian terms - nr3 = coef.get("nr3", []) - d3 = coef.get("d3", []) - t3 = coef.get("t3", []) - a3 = coef.get("alfa3", []) - e3 = coef.get("epsilon3", []) - b3 = coef.get("beta3", []) - g3 = coef.get("gamma3", []) - for n, d, t, a, e, b, g in zip(nr3, d3, t3, a3, e3, b3, g3): - firt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - t/tau-2*b*(tau-g)) - - # Non analitic terms - nr4 = coef.get("nr4", []) - a4 = coef.get("a4", []) - b4 = coef.get("b4", []) - Ai = coef.get("A", []) - Bi = coef.get("B", []) - Ci = coef.get("C", []) - Di = coef.get("D", []) - bt4 = coef.get("beta4", []) - for n, a, b, A, B, C, D, bt in zip(nr4, a4, b4, Ai, Bi, Ci, Di, bt4): - Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) - F = exp(-C*(delta-1)**2-D*(tau-1)**2) - Ft = -2*D*F*(tau-1) - Delta = Tita**2+B*((delta-1)**2)**a - DeltaBt = -2*Tita*b*Delta**(b-1) - firt += n*delta*(DeltaBt*F+Delta**b*Ft) - - return firt + # Gaussian terms + for n, d, t, a, e, b, g in zip(self.nr3, self.d3, self.t3, self.alfa3, + self.epsilon3, self.beta3, self.gamma3): + fir += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2) + + # Non analitic terms + for n, a, b, A, B, C, D, bt in zip(self.nr4, self.a4, self.b4, self.A, + self.B, self.C, self.D, self.beta4): + Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) + F = exp(-C*(delta-1)**2-D*(tau-1)**2) + Delta = Tita**2+B*((delta-1)**2)**a + fir += n*Delta**b*delta*F + + return fir + + def phird(self, tau: float, delta: float) -> float: + r"""Residual contribution to the adimensional free Helmholtz energy, delta + derivative + + Parameters + ---------- + tau : float + Inverse reduced temperature Tc/T, [-] + delta : float + Reduced density rho/rhoc, [-] + coef : dict + Dictionary with equation of state parameters + + Returns + ------- + fird : float + .. math:: + \left.\frac{\partial \phi^r_{\delta}}{\partial \delta}\right|_{\tau} + + References + ---------- + IAPWS, Revised Release on the IAPWS Formulation 1995 for the + Thermodynamic Properties of Ordinary Water Substance for General and + Scientific Use, September 2016, Table 5 + http://www.iapws.org/relguide/IAPWS-95.html + """ + # Ensure parameters are really floats. + tau = float(tau) + delta = float(delta) + + fird = 0.0 + # Polinomial terms + for n, d, t in zip(self.nr1, self.d1, self.t1): + fird += n*d*delta**(d-1)*tau**t + + # Exponential terms + for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): + try: + expt = exp(-g*delta**c) + except OverflowError: + fird = float('nan') + break + fird += n*expt*delta**(d-1)*tau**t*(d-g*c*delta**c) + + # Gaussian terms + for n, d, t, a, e, b, g in zip(self.nr3, self.d3, self.t3, self.alfa3, + self.epsilon3, self.beta3, self.gamma3): + expt = exp(-a*(delta-e)**2-b*(tau-g)**2) + fird += n*delta**d*tau**t*expt*(d/delta-2*a*(delta-e)) + + # Non analitic terms + for n, a, b, A, B, C, D, bt in zip(self.nr4, self.a4, self.b4, self.A, + self.B, self.C, self.D, self.beta4): + Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) + F = exp(-C*(delta-1)**2-D*(tau-1)**2) + Fd = -2*C*F*(delta-1) + + Delta = Tita**2+B*((delta-1)**2)**a + Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**(0.5/bt-1) + + 2*B*a*((delta-1)**2)**(a-1)) + DeltaBd = b*Delta**(b-1)*Deltad + + fird += n*(Delta**b*(F+delta*Fd)+DeltaBd*delta*F) + + return fird + + def phirt(self, tau: float, delta: float) -> float: + r"""Residual contribution to the adimensional free Helmholtz energy, tau + derivative + + Parameters + ---------- + tau : float + Inverse reduced temperature Tc/T, [-] + delta : float + Reduced density rho/rhoc, [-] + coef : dict + Dictionary with equation of state parameters + + Returns + ------- + firt : float + .. math:: + \left.\frac{\partial \phi^r_{\tau}}{\partial \tau}\right|_{\delta} + + References + ---------- + IAPWS, Revised Release on the IAPWS Formulation 1995 for the + Thermodynamic Properties of Ordinary Water Substance for General and + Scientific Use, September 2016, Table 5 + http://www.iapws.org/relguide/IAPWS-95.html + """ + # Ensure parameters are really floats. + tau = float(tau) + delta = float(delta) + + firt = 0.0 + # Polinomial terms + for n, d, t in zip(self.nr1, self.d1, self.t1): + firt += n*t*delta**d*tau**(t-1) + + # Exponential terms + for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): + firt += n*t*delta**d*tau**(t-1)*exp(-g*delta**c) + + # Gaussian terms + for n, d, t, a, e, b, g in zip(self.nr3, self.d3, self.t3, self.alfa3, + self.epsilon3, self.beta3, self.gamma3): + firt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( + t/tau-2*b*(tau-g)) + + # Non analitic terms + for n, a, b, A, B, C, D, bt in zip(self.nr4, self.a4, self.b4, self.A, + self.B, self.C, self.D, self.beta4): + Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) + F = exp(-C*(delta-1)**2-D*(tau-1)**2) + Ft = -2*D*F*(tau-1) + Delta = Tita**2+B*((delta-1)**2)**a + DeltaBt = -2*Tita*b*Delta**(b-1) + firt += n*delta*(DeltaBt*F+Delta**b*Ft) + + return firt + + def helmholtz(self, tau: float, delta: float) -> HelmholtzDerivatives: + """Residual contribution to the free Helmholtz energy + + Parameters + ---------- + tau : float + Inverse reduced temperature Tc/T, [-] + delta : float + Reduced density rho/rhoc, [-] + + Returns + ------- + HelmholtzDerivatives class, with residual adimensional helmholtz + energy and deriv: + * fir + * firt: ∂fir/∂τ|δ,x + * fird: ∂fir/∂δ|τ,x + * firtt: ∂²fir/∂τ²|δ,x + * firdt: ∂²fir/∂τ∂δ|x + * firdd: ∂²fir/∂δ²|τ,x + + References + ---------- + IAPWS, Revised Release on the IAPWS Formulation 1995 for the + Thermodynamic Properties of Ordinary Water Substance for General and + Scientific Use, September 2016, Table 5 + http://www.iapws.org/relguide/IAPWS-95.html + """ + # Ensure parameters are really floats. + tau = float(tau) + delta = float(delta) + + fir = fird = firdd = firt = firtt = firdt = 0.0 + # Polinomial terms + for n, d, t in zip(self.nr1, self.d1, self.t1): + fir += n*delta**d*tau**t + fird += n*d*delta**(d-1)*tau**t + firdd += n*d*(d-1)*delta**(d-2)*tau**t + firt += n*t*delta**d*tau**(t-1) + firtt += n*t*(t-1)*delta**d*tau**(t-2) + firdt += n*t*d*delta**(d-1)*tau**(t-1) + + # Exponential terms + failed = False + for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): + try: + expgdc = exp(-g*delta**c) + except OverflowError: + failed = True + expgdc = float('inf') + fir += n*delta**d*tau**t*expgdc + fird += n*expgdc*delta**(d-1)*tau**t*(d-g*c*delta**c) + firdd += n*expgdc*delta**(d-2)*tau**t * \ + ((d-g*c*delta**c)*(d-1-g*c*delta**c)-g**2*c**2*delta**c) + firt += n*t*delta**d*tau**(t-1)*expgdc + firtt += n*t*(t-1)*delta**d*tau**(t-2)*expgdc + firdt += n*t*delta**(d-1)*tau**(t-1)*(d-g*c*delta**c)*expgdc + if failed: + fir = float('nan') + + # Gaussian terms + for n, d, t, a, e, b, g in zip(self.nr3, self.d3, self.t3, self.alfa3, + self.epsilon3, self.beta3, self.gamma3): + fir += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2) + fird += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( + d/delta-2*a*(delta-e)) + firdd += n*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( + -2*a*delta**d + 4*a**2*delta**d*(delta-e)**2 + - 4*d*a*delta**(d-1)*(delta-e) + d*(d-1)*delta**(d-2)) + firt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( + t/tau-2*b*(tau-g)) + firtt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( + (t/tau-2*b*(tau-g))**2-t/tau**2-2*b) + firdt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( + t/tau-2*b*(tau-g))*(d/delta-2*a*(delta-e)) + + # Non analitic terms + for n, a, b, A, B, C, D, bt in zip(self.nr4, self.a4, self.b4, self.A, + self.B, self.C, self.D, self.beta4): + Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) + F = exp(-C*(delta-1)**2-D*(tau-1)**2) + Fd = -2*C*F*(delta-1) + Fdd = 2*C*F*(2*C*(delta-1)**2-1) + Ft = -2*D*F*(tau-1) + Ftt = 2*D*F*(2*D*(tau-1)**2-1) + Fdt = 4*C*D*F*(delta-1)*(tau-1) + + Delta = Tita**2+B*((delta-1)**2)**a + Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**(0.5/bt-1) + + 2*B*a*((delta-1)**2)**(a-1)) + if delta == 1: + Deltadd = 0 + else: + Deltadd = Deltad/(delta-1)+(delta-1)**2*( + 4*B*a*(a-1)*((delta-1)**2)**(a-2) + + 2*A**2/bt**2*(((delta-1)**2)**(0.5/bt-1))**2 + + A*Tita*4/bt*(0.5/bt-1)*((delta-1)**2)**(0.5/bt-2)) + + DeltaBd = b*Delta**(b-1)*Deltad + DeltaBdd = b*(Delta**(b-1)*Deltadd+(b-1)*Delta**(b-2)*Deltad**2) + DeltaBt = -2*Tita*b*Delta**(b-1) + DeltaBtt = 2*b*Delta**(b-1)+4*Tita**2*b*(b-1)*Delta**(b-2) + DeltaBdt = -A*b*2/bt*Delta**(b-1)*(delta-1)*((delta-1)**2)**( + 0.5/bt-1)-2*Tita*b*(b-1)*Delta**(b-2)*Deltad + + fir += n*Delta**b*delta*F + fird += n*(Delta**b*(F+delta*Fd)+DeltaBd*delta*F) + firdd += n*(Delta**b*(2*Fd+delta*Fdd) + 2*DeltaBd*(F+delta*Fd) + + DeltaBdd*delta*F) + firt += n*delta*(DeltaBt*F+Delta**b*Ft) + firtt += n*delta*(DeltaBtt*F+2*DeltaBt*Ft+Delta**b*Ftt) + firdt += n*(Delta**b*(Ft+delta*Fdt)+delta*DeltaBd*Ft + + DeltaBt*(F+delta*Fd)+DeltaBdt*delta*F) + + return HelmholtzDerivatives(fir, firt, fird, firtt, firdd, firdt) + + def _virial(self, T: float, Tc: float) -> Dict[str, float]: + """Virial coefficient + + Parameters + ---------- + T : float + Temperature [K] + + Returns + ------- + prop : dict + Dictionary with residual adimensional helmholtz energy: + * B: ∂fir/∂δ|δ->0 + * C: ∂²fir/∂δ²|δ->0 + """ + tau = Tc/T + B = C = 0.0 + delta = 1e-200 + + # Polinomial terms + for n, d, t in zip(self.nr1, self.d1, self.t1): + B += n*d*delta**(d-1)*tau**t + C += n*d*(d-1)*delta**(d-2)*tau**t + + # Exponential terms + for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): + B += n*exp(-g*delta**c)*delta**(d-1)*tau**t*(d-g*c*delta**c) + C += n*exp(-g*delta**c)*(delta**(d-2)*tau**t*( + (d-g*c*delta**c)*(d-1-g*c*delta**c)-g**2*c**2*delta**c)) + + # Gaussian terms + for n, d, t, a, e, b, g in zip(self.nr3, self.d3, self.t3, self.alfa3, + self.epsilon3, self.beta3, self.gamma3): + B += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( + d/delta-2*a*(delta-e)) + C += n*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( + -2*a*delta**d+4*a**2*delta**d*( + delta-e)**2-4*d*a*delta**2*( + delta-e)+d*2*delta) + + # Non analitic terms + for n, a, b, A, B_, C_, D, bt in zip(self.nr4, self.a4, self.b4, self.A, + self.B, self.C, self.D, self.beta4): + Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) + Delta = Tita**2+B_*((delta-1)**2)**a + Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**( + 0.5/bt-1)+2*B_*a*((delta-1)**2)**(a-1)) + Deltadd = Deltad/(delta-1) + (delta-1)**2*( + 4*B_*a*(a-1)*((delta-1)**2)**(a-2) + + 2*A**2/bt**2*(((delta-1)**2)**(0.5/bt-1))**2 + + A*Tita*4/bt*(0.5/bt-1)*((delta-1)**2)**(0.5/bt-2)) + DeltaBd = b*Delta**(b-1)*Deltad + DeltaBdd = b*(Delta**(b-1)*Deltadd+(b-1)*Delta**(b-2)*Deltad**2) + F = exp(-C_*(delta-1)**2-D*(tau-1)**2) + Fd = -2*C_*F*(delta-1) + Fdd = 2*C_*F*(2*C_*(delta-1)**2-1) + + B += n*(Delta**b*(F+delta*Fd)+DeltaBd*delta*F) + C += n*(Delta**b*(2*Fd+delta*Fdd)+2*DeltaBd*(F+delta*Fd) + + DeltaBdd*delta*F) + + prop = {} + prop["B"] = B + prop["C"] = C + return prop class MEoSProperties(object): @@ -449,6 +602,7 @@ class MEoS(_fase): Tt: float _constant_R: float _constants: Dict[str, List[float]] + residual: ResidualContribution M: float # The name of the substance. # Set in NH3, Air, IAPWS95, D2O, and IAPWS97. @@ -616,7 +770,7 @@ def rho_func(rho: float) -> float: delta = rho/rhoc tau = Tc/T - fird = _phird(tau, delta, self._constants) + fird = self.residual.phird(tau, delta) Po = (1+delta*fird)*self.R*T*rho return Po-P*1000 @@ -643,8 +797,8 @@ def rho_func(rho: float) -> float: def rho_func(rho: float) -> float: delta = rho/rhoc - fird = _phird(tau, delta, self._constants) - firt = _phirt(tau, delta, self._constants) + fird = self.residual.phird(tau, delta) + firt = self.residual.phirt(tau, delta) ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) return ho-h @@ -658,10 +812,10 @@ def rho_func(rho: float) -> float: deltaL = rhol/rhoc deltaG = rhov/rhoc - firdL = _phird(tau, deltaL, self._constants) - firtL = _phirt(tau, deltaL, self._constants) - firdG = _phird(tau, deltaG, self._constants) - firtG = _phirt(tau, deltaG, self._constants) + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) hl = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) hv = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) if x0 not in (0, 1) and hl <= h <= hv: @@ -689,8 +843,8 @@ def rho_func(rho: float) -> float: delta = rho/rhoc ideal = self._phi0(tau, delta) - fir = _phir(tau, delta, self._constants) - firt = _phirt(tau, delta, self._constants) + fir = self.residual.phir(tau, delta) + firt = self.residual.phirt(tau, delta) so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) return so-s @@ -706,11 +860,11 @@ def rho_func(rho: float) -> float: idealL = self._phi0(tau, deltaL) idealG = self._phi0(tau, deltaG) - firL = _phir(tau, deltaL, self._constants) - firtL = _phirt(tau, deltaL, self._constants) + firL = self.residual.phir(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) sl = self.R*(tau*(idealL.fit+firtL)-idealL.fi-firL) - firG = _phir(tau, deltaG, self._constants) - firtG = _phirt(tau, deltaG, self._constants) + firG = self.residual.phir(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) sv = self.R*(tau*(idealL.fit+firtG)-idealG.fi-firG) if sl <= s <= sv: @@ -736,8 +890,8 @@ def rho_func(rho: float) -> float: def rho_func(rho: float) -> float: delta = rho/rhoc - fird = _phird(tau, delta, self._constants) - firt = _phirt(tau, delta, self._constants) + fird = self.residual.phird(tau, delta) + firt = self.residual.phirt(tau, delta) Po = (1+delta*fird)*self.R*T*rho ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) @@ -752,10 +906,10 @@ def rho_func(rho: float) -> float: deltaL = rhol/rhoc deltaG = rhov/rhoc - firdL = _phird(tau, deltaL, self._constants) - firtL = _phirt(tau, deltaL, self._constants) - firdG = _phird(tau, deltaG, self._constants) - firtG = _phirt(tau, deltaG, self._constants) + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) PoL = (1+deltaL*firdL)*self.R*T*rhol PoG = (1+deltaG*firdG)*self.R*T*rhov hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) @@ -785,7 +939,7 @@ def rho_func(rho: float) -> float: def t_func(T: float) -> float: tau = Tc/T - fird = _phird(tau, delta, self._constants) + fird = self.residual.phird(tau, delta) Po = (1+delta*fird)*self.R*T*rho return Po-P*1000 @@ -800,10 +954,10 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: deltaL = rhol/self._constant_rhoc deltaG = rhog/self._constant_rhoc - firL = _phir(tau, deltaL, self._constants) - firdL = _phird(tau, deltaL, self._constants) - firG = _phir(tau, deltaG, self._constants) - firdG = _phird(tau, deltaG, self._constants) + firL = self.residual.phir(tau, deltaL) + firdL = self.residual.phird(tau, deltaL) + firG = self.residual.phir(tau, deltaG) + firdG = self.residual.phird(tau, deltaG) Jl = rhol*(1+deltaL*firdL) Jv = rhog*(1+deltaG*firdG) @@ -840,8 +994,8 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: tau = Tc/T ideal = self._phi0(tau, delta) - fird = _phird(tau, delta, self._constants) - firt = _phirt(tau, delta, self._constants) + fird = self.residual.phird(tau, delta) + firt = self.residual.phirt(tau, delta) Po = (1+delta*fird)*self.R*T*rho ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) return Po-P*1000, ho-h @@ -860,13 +1014,13 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ ideal = self._phi0(tau, deltaL) - firL = _phir(tau, deltaL, self._constants) - firdL = _phird(tau, deltaL, self._constants) - firtL = _phirt(tau, deltaL, self._constants) + firL = self.residual.phir(tau, deltaL) + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) - firG = _phir(tau, deltaG, self._constants) - firdG = _phird(tau, deltaG, self._constants) - firtG = _phirt(tau, deltaG, self._constants) + firG = self.residual.phir(tau, deltaG) + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) Jl = rhol*(1+deltaL*firdL) @@ -909,9 +1063,9 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: tau = Tc/T ideal = self._phi0(tau, delta) - fird = _phird(tau, delta, self._constants) - fir = _phir(tau, delta, self._constants) - firt = _phirt(tau, delta, self._constants) + fird = self.residual.phird(tau, delta) + fir = self.residual.phir(tau, delta) + firt = self.residual.phirt(tau, delta) Po = (1+delta*fird)*self.R*T*rho so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) return Po-P*1000, so-s @@ -941,8 +1095,8 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: tau = Tc/T ideal = self._phi0(tau, delta) - fird = _phird(tau, delta, self._constants) - firt = _phirt(tau, delta, self._constants) + fird = self.residual.phird(tau, delta) + firt = self.residual.phirt(tau, delta) Po = (1+delta*fird)*self.R*T*rho ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) return ho-Po/rho-u, Po-P*1000 @@ -962,13 +1116,13 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ ideal = self._phi0(tau, deltaL) - firL = _phir(tau, deltaL, self._constants) - firdL = _phird(tau, deltaL, self._constants) - firtL = _phirt(tau, deltaL, self._constants) + firL = self.residual.phir(tau, deltaL) + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) - firG = _phir(tau, deltaG, self._constants) - firdG = _phird(tau, deltaG, self._constants) - firtG = _phirt(tau, deltaG, self._constants) + firG = self.residual.phir(tau, deltaG) + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) Jl = rhol*(1+deltaL*firdL) @@ -1008,8 +1162,8 @@ def t_func(T: float) -> float: tau = Tc/T ideal = self._phi0(tau, delta) - fird = _phird(tau, delta, self._constants) - firt = _phirt(tau, delta, self._constants) + fird = self.residual.phird(tau, delta) + firt = self.residual.phirt(tau, delta) ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) return ho-h @@ -1024,13 +1178,13 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: deltaG = rhog/self._constant_rhoc ideal = self._phi0(tau, deltaL) - firL = _phir(tau, deltaL, self._constants) - firdL = _phird(tau, deltaL, self._constants) - firtL = _phirt(tau, deltaL, self._constants) + firL = self.residual.phir(tau, deltaL) + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) - firG = _phir(tau, deltaG, self._constants) - firdG = _phird(tau, deltaG, self._constants) - firtG = _phirt(tau, deltaG, self._constants) + firG = self.residual.phir(tau, deltaG) + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) Jl = rhol*(1+deltaL*firdL) @@ -1068,8 +1222,8 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: def t_func(T: float) -> float: tau = Tc/T ideal = self._phi0(tau, delta) - fir = _phir(tau, delta, self._constants) - firt = _phirt(tau, delta, self._constants) + fir = self.residual.phir(tau, delta) + firt = self.residual.phirt(tau, delta) so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) return so-s @@ -1087,13 +1241,13 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: idealL = self._phi0(tau, deltaL) idealG = self._phi0(tau, deltaG) - firL = _phir(tau, deltaL, self._constants) - firdL = _phird(tau, deltaL, self._constants) - firtL = _phirt(tau, deltaL, self._constants) + firL = self.residual.phir(tau, deltaL) + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) soL = self.R*(tau*(idealL.fit+firtL)-idealL.fi-firL) - firG = _phir(tau, deltaG, self._constants) - firdG = _phird(tau, deltaG, self._constants) - firtG = _phirt(tau, deltaG, self._constants) + firG = self.residual.phir(tau, deltaG) + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) soG = self.R*(tau*(idealL.fit+firtG)-idealG.fi-firG) Jl = rhol*(1+deltaL*firdL) @@ -1132,8 +1286,8 @@ def t_func(T: float) -> float: tau = Tc/T ideal = self._phi0(tau, delta) - fird = _phird(tau, delta, self._constants) - firt = _phirt(tau, delta, self._constants) + fird = self.residual.phird(tau, delta) + firt = self.residual.phirt(tau, delta) Po = (1+delta*fird)*self.R*T*rho ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) return ho-Po/rho-u @@ -1149,13 +1303,13 @@ def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: deltaG = rhog/self._constant_rhoc ideal = self._phi0(tau, deltaL) - firL = _phir(tau, deltaL, self._constants) - firdL = _phird(tau, deltaL, self._constants) - firtL = _phirt(tau, deltaL, self._constants) + firL = self.residual.phir(tau, deltaL) + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) - firG = _phir(tau, deltaG, self._constants) - firdG = _phird(tau, deltaG, self._constants) - firtG = _phirt(tau, deltaG, self._constants) + firG = self.residual.phir(tau, deltaG) + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) Jl = rhol*(1+deltaL*firdL) @@ -1197,9 +1351,9 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: tau = Tc/T ideal = self._phi0(tau, delta) - fird = _phird(tau, delta, self._constants) - fir = _phir(tau, delta, self._constants) - firt = _phirt(tau, delta, self._constants) + fird = self.residual.phird(tau, delta) + fir = self.residual.phir(tau, delta) + firt = self.residual.phirt(tau, delta) ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) return ho-h, so-s @@ -1219,14 +1373,14 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ idealL = self._phi0(tau, deltaL) idealG = self._phi0(tau, deltaG) - firL = _phir(tau, deltaL, self._constants) - firdL = _phird(tau, deltaL, self._constants) - firtL = _phirt(tau, deltaL, self._constants) + firL = self.residual.phir(tau, deltaL) + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) hoL = self.R*T*(1+tau*(idealL.fit+firtL)+deltaL*firdL) soL = self.R*(tau*(idealL.fit+firtL)-idealL.fi-firL) - firG = _phir(tau, deltaG, self._constants) - firdG = _phird(tau, deltaG, self._constants) - firtG = _phirt(tau, deltaG, self._constants) + firG = self.residual.phir(tau, deltaG) + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) hoG = self.R*T*(1+tau*(idealL.fit+firtG)+deltaG*firdG) soG = self.R*(tau*(idealL.fit+firtG)-idealG.fi-firG) @@ -1262,8 +1416,8 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: tau = Tc/T ideal = self._phi0(tau, delta) - fird = _phird(tau, delta, self._constants) - firt = _phirt(tau, delta, self._constants) + fird = self.residual.phird(tau, delta) + firt = self.residual.phirt(tau, delta) Po = (1+delta*fird)*self.R*T*rho ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) @@ -1284,13 +1438,13 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ ideal = self._phi0(tau, deltaL) - firL = _phir(tau, deltaL, self._constants) - firdL = _phird(tau, deltaL, self._constants) - firtL = _phirt(tau, deltaL, self._constants) + firL = self.residual.phir(tau, deltaL) + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) - firG = _phir(tau, deltaG, self._constants) - firdG = _phird(tau, deltaG, self._constants) - firtG = _phirt(tau, deltaG, self._constants) + firG = self.residual.phir(tau, deltaG) + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) Jl = rhol*(1+deltaL*firdL) @@ -1330,9 +1484,9 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: tau = Tc/T ideal = self._phi0(tau, delta) - fird = _phird(tau, delta, self._constants) - fir = _phir(tau, delta, self._constants) - firt = _phirt(tau, delta, self._constants) + fird = self.residual.phird(tau, delta) + fir = self.residual.phir(tau, delta) + firt = self.residual.phirt(tau, delta) ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) Po = (1+delta*fird)*self.R*T*rho @@ -1354,14 +1508,14 @@ def f4(parr: Tuple[float, float, float, float]) -> Tuple[ idealL = self._phi0(tau, deltaL) idealG = self._phi0(tau, deltaG) - firL = _phir(tau, deltaL, self._constants) - firdL = _phird(tau, deltaL, self._constants) - firtL = _phirt(tau, deltaL, self._constants) + firL = self.residual.phir(tau, deltaL) + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) hoL = self.R*T*(1+tau*(idealL.fit+firtL)+deltaL*firdL) soL = self.R*(tau*(idealL.fit+firtL)-idealL.fi-firL) - firG = _phir(tau, deltaG, self._constants) - firdG = _phird(tau, deltaG, self._constants) - firtG = _phirt(tau, deltaG, self._constants) + firG = self.residual.phir(tau, deltaG) + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) hoG = self.R*T*(1+tau*(idealL.fit+firtG)+deltaG*firdG) soG = self.R*(tau*(idealL.fit+firtG)-idealG.fi-firG) @@ -1450,8 +1604,8 @@ def t_func(T: float) -> float: tau = Tc/T - firL = _phir(tau, deltaL, self._constants) - firG = _phir(tau, deltaG, self._constants) + firL = self.residual.phir(tau, deltaL) + firG = self.residual.phir(tau, deltaG) Ps = self.R*T*rhol*rhog/(rhol-rhog)*( firL-firG+log(deltaL/deltaG)) return Ps/1000-P @@ -1517,7 +1671,7 @@ def t_func(T: float) -> float: else: self.sigma = None - vir = self._virial(T) + vir = self.residual._virial(T, self._constant_Tref) self.virialB = vir["B"]/self._constant_rhoc self.virialC = vir["C"]/self._constant_rhoc**2 @@ -1657,10 +1811,10 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: rhol, rhog = parr deltaL = rhol/rhoc deltaG = rhog/rhoc - phirL = _phir(tau, deltaL, self._constants) - phirG = _phir(tau, deltaG, self._constants) - phirdL = _phird(tau, deltaL, self._constants) - phirdG = _phird(tau, deltaG, self._constants) + phirL = self.residual.phir(tau, deltaL) + phirG = self.residual.phir(tau, deltaG) + phirdL = self.residual.phird(tau, deltaL) + phirdG = self.residual.phird(tau, deltaG) Jl = deltaL*(1+deltaL*phirdL) Jv = deltaG*(1+deltaG*phirdG) Kl = deltaL*phirdL+phirL+log(deltaL) @@ -1673,8 +1827,8 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: else: deltaL = rhoL/self._constant_rhoc deltaG = rhoG/self._constant_rhoc - firL = _phir(tau, deltaL, self._constants) - firG = _phir(tau, deltaG, self._constants) + firL = self.residual.phir(tau, deltaL) + firG = self.residual.phir(tau, deltaG) Ps = self.R*T*rhoL*rhoG/(rhoL-rhoG)*(firL-firG+log(deltaL/deltaG)) return rhoL, rhoG, Ps @@ -1721,7 +1875,7 @@ def _Helmholtz(self, rho: float, T: float) -> MEoSProperties: tau = Tc/T ideal = self._phi0(tau, delta) - res = self._phir(tau, delta) + res = self.residual.helmholtz(tau, delta) P = (1+delta*res.fid)*self.R*T*rho h = self.R*T*(1+tau*(ideal.fit+res.fit)+delta*res.fid) @@ -1826,232 +1980,6 @@ def _phi0(self, tau: float, delta: float) -> HelmholtzDerivatives: return HelmholtzDerivatives(fio, fiot, fiod, fiott, fiodd, fiodt) - def _phir(self, tau: float, delta: float) -> HelmholtzDerivatives: - """Residual contribution to the free Helmholtz energy - - Parameters - ---------- - tau : float - Inverse reduced temperature Tc/T, [-] - delta : float - Reduced density rho/rhoc, [-] - - Returns - ------- - HelmholtzDerivatives class, with residual adimensional helmholtz - energy and deriv: - * fir - * firt: ∂fir/∂τ|δ,x - * fird: ∂fir/∂δ|τ,x - * firtt: ∂²fir/∂τ²|δ,x - * firdt: ∂²fir/∂τ∂δ|x - * firdd: ∂²fir/∂δ²|τ,x - - References - ---------- - IAPWS, Revised Release on the IAPWS Formulation 1995 for the - Thermodynamic Properties of Ordinary Water Substance for General and - Scientific Use, September 2016, Table 5 - http://www.iapws.org/relguide/IAPWS-95.html - """ - fir = fird = firdd = firt = firtt = firdt = 0.0 - - # Convert numpy.Float64 back into Python floats. - tau = float(tau) - delta = float(delta) - - # Polinomial terms - nr1 = self._constants.get("nr1", []) - d1 = self._constants.get("d1", []) - t1 = self._constants.get("t1", []) - for n, d, t in zip(nr1, d1, t1): - fir += n*delta**d*tau**t - fird += n*d*delta**(d-1)*tau**t - firdd += n*d*(d-1)*delta**(d-2)*tau**t - firt += n*t*delta**d*tau**(t-1) - firtt += n*t*(t-1)*delta**d*tau**(t-2) - firdt += n*t*d*delta**(d-1)*tau**(t-1) - - # Exponential terms - nr2 = self._constants.get("nr2", []) - d2 = self._constants.get("d2", []) - g2 = self._constants.get("gamma2", []) - t2 = self._constants.get("t2", []) - c2 = self._constants.get("c2", []) - failed = False - for n, d, g, t, c in zip(nr2, d2, g2, t2, c2): - try: - expgdc = exp(-g*delta**c) - except OverflowError: - failed = True - expgdc = float('inf') - fir += n*delta**d*tau**t*expgdc - fird += n*expgdc*delta**(d-1)*tau**t*(d-g*c*delta**c) - firdd += n*expgdc*delta**(d-2)*tau**t * \ - ((d-g*c*delta**c)*(d-1-g*c*delta**c)-g**2*c**2*delta**c) - firt += n*t*delta**d*tau**(t-1)*expgdc - firtt += n*t*(t-1)*delta**d*tau**(t-2)*expgdc - firdt += n*t*delta**(d-1)*tau**(t-1)*(d-g*c*delta**c)*expgdc - if failed: - fir = float('nan') - - # Gaussian terms - nr3 = self._constants.get("nr3", []) - d3 = self._constants.get("d3", []) - t3 = self._constants.get("t3", []) - a3 = self._constants.get("alfa3", []) - e3 = self._constants.get("epsilon3", []) - b3 = self._constants.get("beta3", []) - g3 = self._constants.get("gamma3", []) - for n, d, t, a, e, b, g in zip(nr3, d3, t3, a3, e3, b3, g3): - fir += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2) - fird += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - d/delta-2*a*(delta-e)) - firdd += n*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - -2*a*delta**d + 4*a**2*delta**d*(delta-e)**2 - - 4*d*a*delta**(d-1)*(delta-e) + d*(d-1)*delta**(d-2)) - firt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - t/tau-2*b*(tau-g)) - firtt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - (t/tau-2*b*(tau-g))**2-t/tau**2-2*b) - firdt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - t/tau-2*b*(tau-g))*(d/delta-2*a*(delta-e)) - - # Non analitic terms - nr4 = self._constants.get("nr4", []) - a4 = self._constants.get("a4", []) - b4 = self._constants.get("b4", []) - Ai = self._constants.get("A", []) - Bi = self._constants.get("B", []) - Ci = self._constants.get("C", []) - Di = self._constants.get("D", []) - bt4 = self._constants.get("beta4", []) - for n, a, b, A, B, C, D, bt in zip(nr4, a4, b4, Ai, Bi, Ci, Di, bt4): - Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) - F = exp(-C*(delta-1)**2-D*(tau-1)**2) - Fd = -2*C*F*(delta-1) - Fdd = 2*C*F*(2*C*(delta-1)**2-1) - Ft = -2*D*F*(tau-1) - Ftt = 2*D*F*(2*D*(tau-1)**2-1) - Fdt = 4*C*D*F*(delta-1)*(tau-1) - - Delta = Tita**2+B*((delta-1)**2)**a - Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**(0.5/bt-1) - + 2*B*a*((delta-1)**2)**(a-1)) - if delta == 1: - Deltadd = 0 - else: - Deltadd = Deltad/(delta-1)+(delta-1)**2*( - 4*B*a*(a-1)*((delta-1)**2)**(a-2) - + 2*A**2/bt**2*(((delta-1)**2)**(0.5/bt-1))**2 - + A*Tita*4/bt*(0.5/bt-1)*((delta-1)**2)**(0.5/bt-2)) - - DeltaBd = b*Delta**(b-1)*Deltad - DeltaBdd = b*(Delta**(b-1)*Deltadd+(b-1)*Delta**(b-2)*Deltad**2) - DeltaBt = -2*Tita*b*Delta**(b-1) - DeltaBtt = 2*b*Delta**(b-1)+4*Tita**2*b*(b-1)*Delta**(b-2) - DeltaBdt = -A*b*2/bt*Delta**(b-1)*(delta-1)*((delta-1)**2)**( - 0.5/bt-1)-2*Tita*b*(b-1)*Delta**(b-2)*Deltad - - fir += n*Delta**b*delta*F - fird += n*(Delta**b*(F+delta*Fd)+DeltaBd*delta*F) - firdd += n*(Delta**b*(2*Fd+delta*Fdd) + 2*DeltaBd*(F+delta*Fd) - + DeltaBdd*delta*F) - firt += n*delta*(DeltaBt*F+Delta**b*Ft) - firtt += n*delta*(DeltaBtt*F+2*DeltaBt*Ft+Delta**b*Ftt) - firdt += n*(Delta**b*(Ft+delta*Fdt)+delta*DeltaBd*Ft - + DeltaBt*(F+delta*Fd)+DeltaBdt*delta*F) - - return HelmholtzDerivatives(fir, firt, fird, firtt, firdd, firdt) - - def _virial(self, T: float) -> Dict[str, float]: - """Virial coefficient - - Parameters - ---------- - T : float - Temperature [K] - - Returns - ------- - prop : dict - Dictionary with residual adimensional helmholtz energy: - * B: ∂fir/∂δ|δ->0 - * C: ∂²fir/∂δ²|δ->0 - """ - Tc = self._constant_Tref - tau = Tc/T - B = C = 0.0 - delta = 1e-200 - - # Polinomial terms - nr1 = self._constants.get("nr1", []) - d1 = self._constants.get("d1", []) - t1 = self._constants.get("t1", []) - for n, d, t in zip(nr1, d1, t1): - B += n*d*delta**(d-1)*tau**t - C += n*d*(d-1)*delta**(d-2)*tau**t - - # Exponential terms - nr2 = self._constants.get("nr2", []) - d2 = self._constants.get("d2", []) - g2 = self._constants.get("gamma2", []) - t2 = self._constants.get("t2", []) - c2 = self._constants.get("c2", []) - for n, d, g, t, c in zip(nr2, d2, g2, t2, c2): - B += n*exp(-g*delta**c)*delta**(d-1)*tau**t*(d-g*c*delta**c) - C += n*exp(-g*delta**c)*(delta**(d-2)*tau**t*( - (d-g*c*delta**c)*(d-1-g*c*delta**c)-g**2*c**2*delta**c)) - - # Gaussian terms - nr3 = self._constants.get("nr3", []) - d3 = self._constants.get("d3", []) - t3 = self._constants.get("t3", []) - a3 = self._constants.get("alfa3", []) - e3 = self._constants.get("epsilon3", []) - b3 = self._constants.get("beta3", []) - g3 = self._constants.get("gamma3", []) - for n, d, t, a, e, b, g in zip(nr3, d3, t3, a3, e3, b3, g3): - B += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - d/delta-2*a*(delta-e)) - C += n*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - -2*a*delta**d+4*a**2*delta**d*( - delta-e)**2-4*d*a*delta**2*( - delta-e)+d*2*delta) - - # Non analitic terms - nr4 = self._constants.get("nr4", []) - a4 = self._constants.get("a4", []) - b4 = self._constants.get("b4", []) - Ai = self._constants.get("A", []) - Bi = self._constants.get("B", []) - Ci = self._constants.get("C", []) - Di = self._constants.get("D", []) - bt4 = self._constants.get("beta4", []) - for n, a, b, A, B_, C_, D, bt in zip(nr4, a4, b4, Ai, Bi, Ci, Di, bt4): - Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) - Delta = Tita**2+B_*((delta-1)**2)**a - Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**( - 0.5/bt-1)+2*B_*a*((delta-1)**2)**(a-1)) - Deltadd = Deltad/(delta-1) + (delta-1)**2*( - 4*B_*a*(a-1)*((delta-1)**2)**(a-2) - + 2*A**2/bt**2*(((delta-1)**2)**(0.5/bt-1))**2 - + A*Tita*4/bt*(0.5/bt-1)*((delta-1)**2)**(0.5/bt-2)) - DeltaBd = b*Delta**(b-1)*Deltad - DeltaBdd = b*(Delta**(b-1)*Deltadd+(b-1)*Delta**(b-2)*Deltad**2) - F = exp(-C_*(delta-1)**2-D*(tau-1)**2) - Fd = -2*C_*F*(delta-1) - Fdd = 2*C_*F*(2*C_*(delta-1)**2-1) - - B += n*(Delta**b*(F+delta*Fd)+DeltaBd*delta*F) - C += n*(Delta**b*(2*Fd+delta*Fdd)+2*DeltaBd*(F+delta*Fd) - + DeltaBdd*delta*F) - - prop = {} - prop["B"] = B - prop["C"] = C - return prop - def _derivDimensional(self, rho: float, T: float) -> HelmholtzDerivatives: """Calcule the dimensional form or Helmholtz free energy derivatives @@ -2091,7 +2019,7 @@ def _derivDimensional(self, rho: float, T: float) -> HelmholtzDerivatives: ideal = self._phi0(tau, delta) - res = self._phir(tau, delta) + res = self.residual.helmholtz(tau, delta) R = self.R @@ -2417,55 +2345,56 @@ class IAPWS95(MEoS): _constant_R = 8.314371357587 _constant_rhoc = rhoc _constant_Tref = Tc - _constants = { - "nr1": [0.12533547935523e-1, 0.78957634722828e1, -0.87803203303561e1, - 0.31802509345418, -0.26145533859358, -0.78199751687981e-2, - 0.88089493102134e-2], - "d1": [1, 1, 1, 2, 2, 3, 4], - "t1": [-0.5, 0.875, 1, 0.5, 0.75, 0.375, 1], - - "nr2": [-0.66856572307965, 0.20433810950965, -0.66212605039687e-4, - -0.19232721156002, -0.25709043003438, 0.16074868486251, - -0.4009282892587e-1, 0.39343422603254e-6, -0.75941377088144e-5, - 0.56250979351888e-3, -0.15608652257135e-4, 0.11537996422951e-8, - .36582165144204e-6, -.13251180074668e-11, -.62639586912454e-9, - -0.10793600908932, 0.17611491008752e-1, 0.22132295167546, - -0.40247669763528, 0.58083399985759, 0.49969146990806e-2, - -0.31358700712549e-1, -0.74315929710341, 0.47807329915480, - 0.20527940895948e-1, -0.13636435110343, 0.14180634400617e-1, - 0.83326504880713e-2, -0.29052336009585e-1, 0.38615085574206e-1, - -0.20393486513704e-1, -0.16554050063734e-2, .19955571979541e-2, - 0.15870308324157e-3, -0.16388568342530e-4, 0.43613615723811e-1, - 0.34994005463765e-1, -0.76788197844621e-1, 0.22446277332006e-1, - -0.62689710414685e-4, -0.55711118565645e-9, -0.19905718354408, - 0.31777497330738, -0.11841182425981], - "c2": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 6, 6, - 6, 6], - "d2": [1, 1, 1, 2, 2, 3, 4, 4, 5, 7, 9, 10, 11, 13, 15, 1, 2, 2, 2, 3, - 4, 4, 4, 5, 6, 6, 7, 9, 9, 9, 9, 9, 10, 10, 12, 3, 4, 4, 5, 14, - 3, 6, 6, 6], - "t2": [4, 6, 12, 1, 5, 4, 2, 13, 9, 3, 4, 11, 4, 13, 1, 7, 1, 9, 10, - 10, 3, 7, 10, 10, 6, 10, 10, 1, 2, 3, 4, 8, 6, 9, 8, 16, 22, 23, - 23, 10, 50, 44, 46, 50], - "gamma2": [1]*44, - - "nr3": [-0.31306260323435e2, 0.31546140237781e2, -0.25213154341695e4], - "d3": [3]*3, - "t3": [0, 1, 4], - "alfa3": [20]*3, - "beta3": [150, 150, 250], - "gamma3": [1.21, 1.21, 1.25], - "epsilon3": [1.]*3, - - "nr4": [-0.14874640856724, 0.31806110878444], - "a4": [3.5, 3.5], - "b4": [0.85, 0.95], - "B": [0.2, 0.2], - "C": [28, 32], - "D": [700, 800], - "A": [0.32, .32], - "beta4": [0.3, 0.3]} + residual = ResidualContribution( + nr1=[0.12533547935523e-1, 0.78957634722828e1, -0.87803203303561e1, + 0.31802509345418, -0.26145533859358, -0.78199751687981e-2, + 0.88089493102134e-2], + d1=[1, 1, 1, 2, 2, 3, 4], + t1=[-0.5, 0.875, 1, 0.5, 0.75, 0.375, 1], + + nr2=[-0.66856572307965, 0.20433810950965, -0.66212605039687e-4, + -0.19232721156002, -0.25709043003438, 0.16074868486251, + -0.4009282892587e-1, 0.39343422603254e-6, -0.75941377088144e-5, + 0.56250979351888e-3, -0.15608652257135e-4, 0.11537996422951e-8, + .36582165144204e-6, -.13251180074668e-11, -.62639586912454e-9, + -0.10793600908932, 0.17611491008752e-1, 0.22132295167546, + -0.40247669763528, 0.58083399985759, 0.49969146990806e-2, + -0.31358700712549e-1, -0.74315929710341, 0.47807329915480, + 0.20527940895948e-1, -0.13636435110343, 0.14180634400617e-1, + 0.83326504880713e-2, -0.29052336009585e-1, 0.38615085574206e-1, + -0.20393486513704e-1, -0.16554050063734e-2, .19955571979541e-2, + 0.15870308324157e-3, -0.16388568342530e-4, 0.43613615723811e-1, + 0.34994005463765e-1, -0.76788197844621e-1, 0.22446277332006e-1, + -0.62689710414685e-4, -0.55711118565645e-9, -0.19905718354408, + 0.31777497330738, -0.11841182425981], + c2=[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 6, 6, + 6, 6], + d2=[1, 1, 1, 2, 2, 3, 4, 4, 5, 7, 9, 10, 11, 13, 15, 1, 2, 2, 2, 3, + 4, 4, 4, 5, 6, 6, 7, 9, 9, 9, 9, 9, 10, 10, 12, 3, 4, 4, 5, 14, + 3, 6, 6, 6], + t2=[4, 6, 12, 1, 5, 4, 2, 13, 9, 3, 4, 11, 4, 13, 1, 7, 1, 9, 10, + 10, 3, 7, 10, 10, 6, 10, 10, 1, 2, 3, 4, 8, 6, 9, 8, 16, 22, 23, + 23, 10, 50, 44, 46, 50], + gamma2=[1]*44, + + nr3=[-0.31306260323435e2, 0.31546140237781e2, -0.25213154341695e4], + d3=[3]*3, + t3=[0, 1, 4], + alfa3=[20]*3, + beta3=[150, 150, 250], + gamma3=[1.21, 1.21, 1.25], + epsilon3=[1.]*3, + + nr4=[-0.14874640856724, 0.31806110878444], + a4=[3.5, 3.5], + b4=[0.85, 0.95], + B=[0.2, 0.2], + C=[28, 32], + D=[700, 800], + A=[0.32, .32], + beta4=[0.3, 0.3], + ) _Pv_ao = [-7.85951783, 1.84408259, -11.7866497, 22.6807411, -15.9618719, 1.80122502] @@ -2769,33 +2698,34 @@ class D2O(MEoS): _constant_R = 8.3144598 _constant_rhoc = rhoc_D2O _constant_Tref = Tc_D2O - _constants = { - "nr1": [0.122082060e-1, 0.296956870e1, -0.379004540e1, 0.941089600, - -0.922466250, -0.139604190e-1], - "d1": [4, 1, 1, 2, 2, 3], - "t1": [1.0000, 0.6555, 0.9369, 0.5610, 0.7017, 1.0672], - - "nr2": [-0.125203570, -0.555391500e1, -0.493009740e1, -0.359470240e-1, - -0.936172870e1, -0.691835150], - "c2": [1, 2, 2, 1, 2, 2], - "d2": [1, 1, 3, 2, 2, 1], - "t2": [3.9515, 4.6000, 5.1590, 0.2000, 5.4644, 2.3660], - "gamma2": [1]*6, - - "nr3": [-0.456110600e-1, -0.224513300e1, 0.860006070e1, -0.248410420e1, - 0.164476900e2, 0.270393360e1, 0.375637470e2, -0.177607760e1, - 0.220924640e1, 0.519652000e1, 0.421097400, -0.391921100], - "t3": [3.4553, 1.4150, 1.5745, 3.4540, 3.8106, 4.8950, 1.4300, 1.5870, - 3.7900, 2.6200, 1.9000, 4.3200], - "d3": [1, 3, 1, 3, 1, 1, 2, 2, 2, 1, 1, 1], - "alfa3": [0.6014, 1.4723, 1.5305, 2.4297, 1.3086, 1.3528, 3.4456, - 1.2645, 2.5547, 1.2148, 18.738, 18.677], - "beta3": [0.4200, 2.4318, 1.2888, 8.2710, 0.3673, 0.9504, 7.8318, - 3.3281, 7.1753, 0.9465, 1177.0, 1167.0], - "epsilon3": [1.8663, 0.2895, 0.5803, 0.2236, 0.6815, 0.9495, 1.1158, - 0.1607, 0.4144, 0.9683, 0.9488, 0.9487], - "gamma3": [1.5414, 1.3794, 1.7385, 1.3045, 2.7242, 3.5321, 2.4552, - 0.8319, 1.3500, 2.5617, 1.0491, 1.0486]} + residual = ResidualContribution( + nr1=[0.122082060e-1, 0.296956870e1, -0.379004540e1, 0.941089600, + -0.922466250, -0.139604190e-1], + d1=[4, 1, 1, 2, 2, 3], + t1=[1.0000, 0.6555, 0.9369, 0.5610, 0.7017, 1.0672], + nr2=[-0.125203570, -0.555391500e1, -0.493009740e1, -0.359470240e-1, + -0.936172870e1, -0.691835150], + c2=[1, 2, 2, 1, 2, 2], + d2=[1, 1, 3, 2, 2, 1], + t2=[3.9515, 4.6000, 5.1590, 0.2000, 5.4644, 2.3660], + gamma2=[1]*6, + + nr3=[-0.456110600e-1, -0.224513300e1, 0.860006070e1, -0.248410420e1, + 0.164476900e2, 0.270393360e1, 0.375637470e2, -0.177607760e1, + 0.220924640e1, 0.519652000e1, 0.421097400, -0.391921100], + t3=[3.4553, 1.4150, 1.5745, 3.4540, 3.8106, 4.8950, 1.4300, 1.5870, + 3.7900, 2.6200, 1.9000, 4.3200], + d3=[1, 3, 1, 3, 1, 1, 2, 2, 2, 1, 1, 1], + alfa3=[0.6014, 1.4723, 1.5305, 2.4297, 1.3086, 1.3528, 3.4456, + 1.2645, 2.5547, 1.2148, 18.738, 18.677], + beta3=[0.4200, 2.4318, 1.2888, 8.2710, 0.3673, 0.9504, 7.8318, + 3.3281, 7.1753, 0.9465, 1177.0, 1167.0], + epsilon3=[1.8663, 0.2895, 0.5803, 0.2236, 0.6815, 0.9495, 1.1158, + 0.1607, 0.4144, 0.9683, 0.9488, 0.9487], + gamma3=[1.5414, 1.3794, 1.7385, 1.3045, 2.7242, 3.5321, 2.4552, + 0.8319, 1.3500, 2.5617, 1.0491, 1.0486], + nr4=[], a4=[], b4=[], A=[], B=[], C=[], D=[], beta4=[], + ) _Pv_ao = [-0.80236e1, 0.23957e1, -0.42639e2, 0.99569e2, -0.62135e2] _Pv_exp = [1.0, 1.5, 2.75, 3.0, 3.2] diff --git a/test.py b/test.py index ac35d9f..af53136 100755 --- a/test.py +++ b/test.py @@ -59,7 +59,7 @@ def test_Helmholtz(self) -> None: self.assertEqual(round(ideal.fitt, 8), -1.93249185) self.assertEqual(round(ideal.fidt, 8), 0.0) - res = fluid._phir(tau, delta) + res = fluid.residual.helmholtz(tau, delta) self.assertEqual(round(res.fi, 8), -3.42693206) self.assertEqual(round(res.fid, 9), -0.364366650) self.assertEqual(round(res.fidd, 9), 0.856063701) @@ -69,7 +69,7 @@ def test_Helmholtz(self) -> None: # Revised release of 2018 # Virial coefficient in Table 3 - vir = fluid._virial(600) + vir = fluid.residual._virial(600, fluid.Tc) self.assertEqual(round(vir["B"]/fluid.rhoc, 11), -0.555366808e-2) self.assertEqual(round(vir["C"]/fluid.rhoc**2, 14), -0.669015050e-5) @@ -1259,7 +1259,7 @@ def test_D2O(self) -> None: self.assertEqual(round(ideal.fit, 8), 9.39259413) self.assertEqual(round(ideal.fitt, 8), -2.09517144) self.assertEqual(round(ideal.fidt, 8), 0) - res = fluid._phir(tau, delta) + res = fluid.residual.helmholtz(tau, delta) self.assertEqual(round(res.fi, 8), -3.42291092) self.assertEqual(round(res.fid, 9), -0.367562780) self.assertEqual(round(res.fidd, 9), 0.835183806) From fb92eb749805cd1ccf710cf85da3bcc46ca390af Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Fri, 19 Mar 2021 21:15:11 -0400 Subject: [PATCH 095/102] Break new class out into a separate file. IAPWS95 is rather larger than I think is comfortable, and so I took this opportunity to break a clearly delinated class out into a new file. --- iapws/_utils.py | 13 -- iapws/ammonia.py | 3 +- iapws/helmholtz.py | 416 +++++++++++++++++++++++++++++++++++++++++++++ iapws/humidAir.py | 3 +- iapws/iapws95.py | 400 +------------------------------------------ 5 files changed, 422 insertions(+), 413 deletions(-) create mode 100644 iapws/helmholtz.py diff --git a/iapws/_utils.py b/iapws/_utils.py index 980d55e..8dce5b7 100644 --- a/iapws/_utils.py +++ b/iapws/_utils.py @@ -233,19 +233,6 @@ def deriv_H(state: Any, z: str, x: str, y: str, fase: _fase) -> float: return mul*deriv -class HelmholtzDerivatives(object): - """Helmholtz free energy and derivatives.""" - - def __init__(self, fi: float, fit: float, fid: float, - fitt: float, fidd: float, fidt: float) -> None: - self.fi = fi - self.fit = fit - self.fid = fid - self.fitt = fitt - self.fidd = fidd - self.fidt = fidt - - def deriv_G(state: Any, z: str, x: str, y: str, fase: _fase) -> float: r"""Calculate generic partial derivative :math:`\left.\frac{\partial z}{\partial x}\right|_{y}` from a fundamental diff --git a/iapws/ammonia.py b/iapws/ammonia.py index 8c7b578..dba6a66 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -16,8 +16,9 @@ from typing import Dict, Optional from scipy.constants import Boltzmann -from .iapws95 import MEoS, IAPWS95, mainClassDoc, ResidualContribution +from .iapws95 import MEoS, IAPWS95, mainClassDoc from ._utils import _fase +from .helmholtz import ResidualContribution @mainClassDoc() diff --git a/iapws/helmholtz.py b/iapws/helmholtz.py new file mode 100644 index 0000000..db13379 --- /dev/null +++ b/iapws/helmholtz.py @@ -0,0 +1,416 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +"""Calculations related to free Helmholtz Energy.""" + +from typing import Dict, List +from math import exp + + +class HelmholtzDerivatives(object): + """Helmholtz free energy and derivatives.""" + + def __init__(self, fi: float, fit: float, fid: float, + fitt: float, fidd: float, fidt: float) -> None: + self.fi = fi + self.fit = fit + self.fid = fid + self.fitt = fitt + self.fidd = fidd + self.fidt = fidt + + +class ResidualContribution(object): + """Residual contribution to the adimensional free Helmholtz energy""" + + def __init__(self, nr1: List[float], d1: List[float], t1: List[float], + nr2: List[float], d2: List[float], gamma2: List[int], + t2: List[float], c2: List[int], nr3: List[float], + d3: List[int], t3: List[float], alfa3: List[float], + epsilon3: List[float], beta3: List[float], gamma3: List[float], + nr4: List[float], a4: List[float], b4: List[float], + A: List[float], B: List[float], C: List[int], + D: List[int], beta4: List[float]) -> None: + # Polinomial terms + self.nr1 = nr1 + self.d1 = d1 + self.t1 = t1 + # Exponential terms + self.nr2 = nr2 + self.d2 = d2 + self.gamma2 = gamma2 # Gamma2 is always ones? + self.t2 = t2 + self.c2 = c2 + # Gaussian terms (optional, may be empty lists) + self.nr3 = nr3 + self.d3 = d3 + self.t3 = t3 + self.alfa3 = alfa3 + self.epsilon3 = epsilon3 + self.beta3 = beta3 + self.gamma3 = gamma3 + # Non analitic terms (optional, may be empty lists) + self.nr4 = nr4 + self.a4 = a4 + self.b4 = b4 + self.A = A + self.B = B + self.C = C + self.D = D + self.beta4 = beta4 + + def phir(self, tau: float, delta: float) -> float: + """Residual contribution to the adimensional free Helmholtz energy + + Parameters + ---------- + tau : float + Inverse reduced temperature Tc/T, [-] + delta : float + Reduced density rho/rhoc, [-] + coef : dict + Dictionary with equation of state parameters + + Returns + ------- + fir : float + Adimensional free Helmholtz energy + + References + ---------- + IAPWS, Revised Release on the IAPWS Formulation 1995 for the + Thermodynamic Properties of Ordinary Water Substance for General and + Scientific Use, September 2016, Table 5 + http://www.iapws.org/relguide/IAPWS-95.html + """ + # Ensure parameters are really floats. + tau = float(tau) + delta = float(delta) + + fir = 0.0 + # Polinomial terms + for n, d, t in zip(self.nr1, self.d1, self.t1): + fir += n*delta**d*tau**t + + # Exponential terms + for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): + fir += n*delta**d*tau**t*exp(-g*delta**c) + + # Gaussian terms + for n, d, t, a, e, b, g in zip(self.nr3, self.d3, self.t3, self.alfa3, + self.epsilon3, self.beta3, self.gamma3): + fir += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2) + + # Non analitic terms + for n, a, b, A, B, C, D, bt in zip(self.nr4, self.a4, self.b4, self.A, + self.B, self.C, self.D, self.beta4): + Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) + F = exp(-C*(delta-1)**2-D*(tau-1)**2) + Delta = Tita**2+B*((delta-1)**2)**a + fir += n*Delta**b*delta*F + + return fir + + def phird(self, tau: float, delta: float) -> float: + r"""Residual contribution to the adimensional free Helmholtz energy, delta + derivative + + Parameters + ---------- + tau : float + Inverse reduced temperature Tc/T, [-] + delta : float + Reduced density rho/rhoc, [-] + coef : dict + Dictionary with equation of state parameters + + Returns + ------- + fird : float + .. math:: + \left.\frac{\partial \phi^r_{\delta}}{\partial \delta}\right|_{\tau} + + References + ---------- + IAPWS, Revised Release on the IAPWS Formulation 1995 for the + Thermodynamic Properties of Ordinary Water Substance for General and + Scientific Use, September 2016, Table 5 + http://www.iapws.org/relguide/IAPWS-95.html + """ + # Ensure parameters are really floats. + tau = float(tau) + delta = float(delta) + + fird = 0.0 + # Polinomial terms + for n, d, t in zip(self.nr1, self.d1, self.t1): + fird += n*d*delta**(d-1)*tau**t + + # Exponential terms + for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): + try: + expt = exp(-g*delta**c) + except OverflowError: + fird = float('nan') + break + fird += n*expt*delta**(d-1)*tau**t*(d-g*c*delta**c) + + # Gaussian terms + for n, d, t, a, e, b, g in zip(self.nr3, self.d3, self.t3, self.alfa3, + self.epsilon3, self.beta3, self.gamma3): + expt = exp(-a*(delta-e)**2-b*(tau-g)**2) + fird += n*delta**d*tau**t*expt*(d/delta-2*a*(delta-e)) + + # Non analitic terms + for n, a, b, A, B, C, D, bt in zip(self.nr4, self.a4, self.b4, self.A, + self.B, self.C, self.D, self.beta4): + Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) + F = exp(-C*(delta-1)**2-D*(tau-1)**2) + Fd = -2*C*F*(delta-1) + + Delta = Tita**2+B*((delta-1)**2)**a + Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**(0.5/bt-1) + + 2*B*a*((delta-1)**2)**(a-1)) + DeltaBd = b*Delta**(b-1)*Deltad + + fird += n*(Delta**b*(F+delta*Fd)+DeltaBd*delta*F) + + return fird + + def phirt(self, tau: float, delta: float) -> float: + r"""Residual contribution to the adimensional free Helmholtz energy, tau + derivative + + Parameters + ---------- + tau : float + Inverse reduced temperature Tc/T, [-] + delta : float + Reduced density rho/rhoc, [-] + coef : dict + Dictionary with equation of state parameters + + Returns + ------- + firt : float + .. math:: + \left.\frac{\partial \phi^r_{\tau}}{\partial \tau}\right|_{\delta} + + References + ---------- + IAPWS, Revised Release on the IAPWS Formulation 1995 for the + Thermodynamic Properties of Ordinary Water Substance for General and + Scientific Use, September 2016, Table 5 + http://www.iapws.org/relguide/IAPWS-95.html + """ + # Ensure parameters are really floats. + tau = float(tau) + delta = float(delta) + + firt = 0.0 + # Polinomial terms + for n, d, t in zip(self.nr1, self.d1, self.t1): + firt += n*t*delta**d*tau**(t-1) + + # Exponential terms + for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): + firt += n*t*delta**d*tau**(t-1)*exp(-g*delta**c) + + # Gaussian terms + for n, d, t, a, e, b, g in zip(self.nr3, self.d3, self.t3, self.alfa3, + self.epsilon3, self.beta3, self.gamma3): + firt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( + t/tau-2*b*(tau-g)) + + # Non analitic terms + for n, a, b, A, B, C, D, bt in zip(self.nr4, self.a4, self.b4, self.A, + self.B, self.C, self.D, self.beta4): + Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) + F = exp(-C*(delta-1)**2-D*(tau-1)**2) + Ft = -2*D*F*(tau-1) + Delta = Tita**2+B*((delta-1)**2)**a + DeltaBt = -2*Tita*b*Delta**(b-1) + firt += n*delta*(DeltaBt*F+Delta**b*Ft) + + return firt + + def helmholtz(self, tau: float, delta: float) -> HelmholtzDerivatives: + """Residual contribution to the free Helmholtz energy + + Parameters + ---------- + tau : float + Inverse reduced temperature Tc/T, [-] + delta : float + Reduced density rho/rhoc, [-] + + Returns + ------- + HelmholtzDerivatives class, with residual adimensional helmholtz + energy and deriv: + * fir + * firt: ∂fir/∂τ|δ,x + * fird: ∂fir/∂δ|τ,x + * firtt: ∂²fir/∂τ²|δ,x + * firdt: ∂²fir/∂τ∂δ|x + * firdd: ∂²fir/∂δ²|τ,x + + References + ---------- + IAPWS, Revised Release on the IAPWS Formulation 1995 for the + Thermodynamic Properties of Ordinary Water Substance for General and + Scientific Use, September 2016, Table 5 + http://www.iapws.org/relguide/IAPWS-95.html + """ + # Ensure parameters are really floats. + tau = float(tau) + delta = float(delta) + + fir = fird = firdd = firt = firtt = firdt = 0.0 + # Polinomial terms + for n, d, t in zip(self.nr1, self.d1, self.t1): + fir += n*delta**d*tau**t + fird += n*d*delta**(d-1)*tau**t + firdd += n*d*(d-1)*delta**(d-2)*tau**t + firt += n*t*delta**d*tau**(t-1) + firtt += n*t*(t-1)*delta**d*tau**(t-2) + firdt += n*t*d*delta**(d-1)*tau**(t-1) + + # Exponential terms + failed = False + for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): + try: + expgdc = exp(-g*delta**c) + except OverflowError: + failed = True + expgdc = float('inf') + fir += n*delta**d*tau**t*expgdc + fird += n*expgdc*delta**(d-1)*tau**t*(d-g*c*delta**c) + firdd += n*expgdc*delta**(d-2)*tau**t * \ + ((d-g*c*delta**c)*(d-1-g*c*delta**c)-g**2*c**2*delta**c) + firt += n*t*delta**d*tau**(t-1)*expgdc + firtt += n*t*(t-1)*delta**d*tau**(t-2)*expgdc + firdt += n*t*delta**(d-1)*tau**(t-1)*(d-g*c*delta**c)*expgdc + if failed: + fir = float('nan') + + # Gaussian terms + for n, d, t, a, e, b, g in zip(self.nr3, self.d3, self.t3, self.alfa3, + self.epsilon3, self.beta3, self.gamma3): + fir += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2) + fird += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( + d/delta-2*a*(delta-e)) + firdd += n*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( + -2*a*delta**d + 4*a**2*delta**d*(delta-e)**2 + - 4*d*a*delta**(d-1)*(delta-e) + d*(d-1)*delta**(d-2)) + firt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( + t/tau-2*b*(tau-g)) + firtt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( + (t/tau-2*b*(tau-g))**2-t/tau**2-2*b) + firdt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( + t/tau-2*b*(tau-g))*(d/delta-2*a*(delta-e)) + + # Non analitic terms + for n, a, b, A, B, C, D, bt in zip(self.nr4, self.a4, self.b4, self.A, + self.B, self.C, self.D, self.beta4): + Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) + F = exp(-C*(delta-1)**2-D*(tau-1)**2) + Fd = -2*C*F*(delta-1) + Fdd = 2*C*F*(2*C*(delta-1)**2-1) + Ft = -2*D*F*(tau-1) + Ftt = 2*D*F*(2*D*(tau-1)**2-1) + Fdt = 4*C*D*F*(delta-1)*(tau-1) + + Delta = Tita**2+B*((delta-1)**2)**a + Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**(0.5/bt-1) + + 2*B*a*((delta-1)**2)**(a-1)) + if delta == 1: + Deltadd = 0 + else: + Deltadd = Deltad/(delta-1)+(delta-1)**2*( + 4*B*a*(a-1)*((delta-1)**2)**(a-2) + + 2*A**2/bt**2*(((delta-1)**2)**(0.5/bt-1))**2 + + A*Tita*4/bt*(0.5/bt-1)*((delta-1)**2)**(0.5/bt-2)) + + DeltaBd = b*Delta**(b-1)*Deltad + DeltaBdd = b*(Delta**(b-1)*Deltadd+(b-1)*Delta**(b-2)*Deltad**2) + DeltaBt = -2*Tita*b*Delta**(b-1) + DeltaBtt = 2*b*Delta**(b-1)+4*Tita**2*b*(b-1)*Delta**(b-2) + DeltaBdt = -A*b*2/bt*Delta**(b-1)*(delta-1)*((delta-1)**2)**( + 0.5/bt-1)-2*Tita*b*(b-1)*Delta**(b-2)*Deltad + + fir += n*Delta**b*delta*F + fird += n*(Delta**b*(F+delta*Fd)+DeltaBd*delta*F) + firdd += n*(Delta**b*(2*Fd+delta*Fdd) + 2*DeltaBd*(F+delta*Fd) + + DeltaBdd*delta*F) + firt += n*delta*(DeltaBt*F+Delta**b*Ft) + firtt += n*delta*(DeltaBtt*F+2*DeltaBt*Ft+Delta**b*Ftt) + firdt += n*(Delta**b*(Ft+delta*Fdt)+delta*DeltaBd*Ft + + DeltaBt*(F+delta*Fd)+DeltaBdt*delta*F) + + return HelmholtzDerivatives(fir, firt, fird, firtt, firdd, firdt) + + def _virial(self, T: float, Tc: float) -> Dict[str, float]: + """Virial coefficient + + Parameters + ---------- + T : float + Temperature [K] + + Returns + ------- + prop : dict + Dictionary with residual adimensional helmholtz energy: + * B: ∂fir/∂δ|δ->0 + * C: ∂²fir/∂δ²|δ->0 + """ + tau = Tc/T + B = C = 0.0 + delta = 1e-200 + + # Polinomial terms + for n, d, t in zip(self.nr1, self.d1, self.t1): + B += n*d*delta**(d-1)*tau**t + C += n*d*(d-1)*delta**(d-2)*tau**t + + # Exponential terms + for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): + B += n*exp(-g*delta**c)*delta**(d-1)*tau**t*(d-g*c*delta**c) + C += n*exp(-g*delta**c)*(delta**(d-2)*tau**t*( + (d-g*c*delta**c)*(d-1-g*c*delta**c)-g**2*c**2*delta**c)) + + # Gaussian terms + for n, d, t, a, e, b, g in zip(self.nr3, self.d3, self.t3, self.alfa3, + self.epsilon3, self.beta3, self.gamma3): + B += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( + d/delta-2*a*(delta-e)) + C += n*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( + -2*a*delta**d+4*a**2*delta**d*( + delta-e)**2-4*d*a*delta**2*( + delta-e)+d*2*delta) + + # Non analitic terms + for n, a, b, A, B_, C_, D, bt in zip(self.nr4, self.a4, self.b4, self.A, + self.B, self.C, self.D, self.beta4): + Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) + Delta = Tita**2+B_*((delta-1)**2)**a + Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**( + 0.5/bt-1)+2*B_*a*((delta-1)**2)**(a-1)) + Deltadd = Deltad/(delta-1) + (delta-1)**2*( + 4*B_*a*(a-1)*((delta-1)**2)**(a-2) + + 2*A**2/bt**2*(((delta-1)**2)**(0.5/bt-1))**2 + + A*Tita*4/bt*(0.5/bt-1)*((delta-1)**2)**(0.5/bt-2)) + DeltaBd = b*Delta**(b-1)*Deltad + DeltaBdd = b*(Delta**(b-1)*Deltadd+(b-1)*Delta**(b-2)*Deltad**2) + F = exp(-C_*(delta-1)**2-D*(tau-1)**2) + Fd = -2*C_*F*(delta-1) + Fdd = 2*C_*F*(2*C_*(delta-1)**2-1) + + B += n*(Delta**b*(F+delta*Fd)+DeltaBd*delta*F) + C += n*(Delta**b*(2*Fd+delta*Fdd)+2*DeltaBd*(F+delta*Fd) + + DeltaBdd*delta*F) + + prop = {} + prop["B"] = B + prop["C"] = C + return prop diff --git a/iapws/humidAir.py b/iapws/humidAir.py index ff4b866..4ec68b9 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -23,7 +23,8 @@ from ._iapws import _global_M from ._iapws import _Ice from ._utils import _fase, deriv_G -from .iapws95 import MEoS, IAPWS95, mainClassDoc, ResidualContribution +from .iapws95 import MEoS, IAPWS95, mainClassDoc +from .helmholtz import ResidualContribution Ma = 28.96546 # g/mol diff --git a/iapws/iapws95.py b/iapws/iapws95.py index f1b5dd1..ddabf82 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -22,404 +22,8 @@ from ._iapws import _global_M, Tc, Pc, rhoc, Tc_D2O, Pc_D2O, rhoc_D2O from ._iapws import _Viscosity, _ThCond, _Dielectric, _Refractive, _Tension from ._iapws import _D2O_Viscosity, _D2O_ThCond, _D2O_Tension -from ._utils import _fase, getphase, deriv_H, HelmholtzDerivatives - - -class ResidualContribution(object): - """Residual contribution to the adimensional free Helmholtz energy""" - - def __init__(self, nr1: List[float], d1: List[float], t1: List[float], - nr2: List[float], d2: List[float], gamma2: List[int], - t2: List[float], c2: List[int], nr3: List[float], - d3: List[int], t3: List[float], alfa3: List[float], - epsilon3: List[float], beta3: List[float], gamma3: List[float], - nr4: List[float], a4: List[float], b4: List[float], - A: List[float], B: List[float], C: List[int], - D: List[int], beta4: List[float]) -> None: - # Polinomial terms - self.nr1 = nr1 - self.d1 = d1 - self.t1 = t1 - # Exponential terms - self.nr2 = nr2 - self.d2 = d2 - self.gamma2 = gamma2 # Gamma2 is always ones? - self.t2 = t2 - self.c2 = c2 - # Gaussian terms (optional, may be empty lists) - self.nr3 = nr3 - self.d3 = d3 - self.t3 = t3 - self.alfa3 = alfa3 - self.epsilon3 = epsilon3 - self.beta3 = beta3 - self.gamma3 = gamma3 - # Non analitic terms (optional, may be empty lists) - self.nr4 = nr4 - self.a4 = a4 - self.b4 = b4 - self.A = A - self.B = B - self.C = C - self.D = D - self.beta4 = beta4 - - def phir(self, tau: float, delta: float) -> float: - """Residual contribution to the adimensional free Helmholtz energy - - Parameters - ---------- - tau : float - Inverse reduced temperature Tc/T, [-] - delta : float - Reduced density rho/rhoc, [-] - coef : dict - Dictionary with equation of state parameters - - Returns - ------- - fir : float - Adimensional free Helmholtz energy - - References - ---------- - IAPWS, Revised Release on the IAPWS Formulation 1995 for the - Thermodynamic Properties of Ordinary Water Substance for General and - Scientific Use, September 2016, Table 5 - http://www.iapws.org/relguide/IAPWS-95.html - """ - # Ensure parameters are really floats. - tau = float(tau) - delta = float(delta) - - fir = 0.0 - # Polinomial terms - for n, d, t in zip(self.nr1, self.d1, self.t1): - fir += n*delta**d*tau**t - - # Exponential terms - for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): - fir += n*delta**d*tau**t*exp(-g*delta**c) - - # Gaussian terms - for n, d, t, a, e, b, g in zip(self.nr3, self.d3, self.t3, self.alfa3, - self.epsilon3, self.beta3, self.gamma3): - fir += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2) - - # Non analitic terms - for n, a, b, A, B, C, D, bt in zip(self.nr4, self.a4, self.b4, self.A, - self.B, self.C, self.D, self.beta4): - Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) - F = exp(-C*(delta-1)**2-D*(tau-1)**2) - Delta = Tita**2+B*((delta-1)**2)**a - fir += n*Delta**b*delta*F - - return fir - - def phird(self, tau: float, delta: float) -> float: - r"""Residual contribution to the adimensional free Helmholtz energy, delta - derivative - - Parameters - ---------- - tau : float - Inverse reduced temperature Tc/T, [-] - delta : float - Reduced density rho/rhoc, [-] - coef : dict - Dictionary with equation of state parameters - - Returns - ------- - fird : float - .. math:: - \left.\frac{\partial \phi^r_{\delta}}{\partial \delta}\right|_{\tau} - - References - ---------- - IAPWS, Revised Release on the IAPWS Formulation 1995 for the - Thermodynamic Properties of Ordinary Water Substance for General and - Scientific Use, September 2016, Table 5 - http://www.iapws.org/relguide/IAPWS-95.html - """ - # Ensure parameters are really floats. - tau = float(tau) - delta = float(delta) - - fird = 0.0 - # Polinomial terms - for n, d, t in zip(self.nr1, self.d1, self.t1): - fird += n*d*delta**(d-1)*tau**t - - # Exponential terms - for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): - try: - expt = exp(-g*delta**c) - except OverflowError: - fird = float('nan') - break - fird += n*expt*delta**(d-1)*tau**t*(d-g*c*delta**c) - - # Gaussian terms - for n, d, t, a, e, b, g in zip(self.nr3, self.d3, self.t3, self.alfa3, - self.epsilon3, self.beta3, self.gamma3): - expt = exp(-a*(delta-e)**2-b*(tau-g)**2) - fird += n*delta**d*tau**t*expt*(d/delta-2*a*(delta-e)) - - # Non analitic terms - for n, a, b, A, B, C, D, bt in zip(self.nr4, self.a4, self.b4, self.A, - self.B, self.C, self.D, self.beta4): - Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) - F = exp(-C*(delta-1)**2-D*(tau-1)**2) - Fd = -2*C*F*(delta-1) - - Delta = Tita**2+B*((delta-1)**2)**a - Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**(0.5/bt-1) - + 2*B*a*((delta-1)**2)**(a-1)) - DeltaBd = b*Delta**(b-1)*Deltad - - fird += n*(Delta**b*(F+delta*Fd)+DeltaBd*delta*F) - - return fird - - def phirt(self, tau: float, delta: float) -> float: - r"""Residual contribution to the adimensional free Helmholtz energy, tau - derivative - - Parameters - ---------- - tau : float - Inverse reduced temperature Tc/T, [-] - delta : float - Reduced density rho/rhoc, [-] - coef : dict - Dictionary with equation of state parameters - - Returns - ------- - firt : float - .. math:: - \left.\frac{\partial \phi^r_{\tau}}{\partial \tau}\right|_{\delta} - - References - ---------- - IAPWS, Revised Release on the IAPWS Formulation 1995 for the - Thermodynamic Properties of Ordinary Water Substance for General and - Scientific Use, September 2016, Table 5 - http://www.iapws.org/relguide/IAPWS-95.html - """ - # Ensure parameters are really floats. - tau = float(tau) - delta = float(delta) - - firt = 0.0 - # Polinomial terms - for n, d, t in zip(self.nr1, self.d1, self.t1): - firt += n*t*delta**d*tau**(t-1) - - # Exponential terms - for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): - firt += n*t*delta**d*tau**(t-1)*exp(-g*delta**c) - - # Gaussian terms - for n, d, t, a, e, b, g in zip(self.nr3, self.d3, self.t3, self.alfa3, - self.epsilon3, self.beta3, self.gamma3): - firt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - t/tau-2*b*(tau-g)) - - # Non analitic terms - for n, a, b, A, B, C, D, bt in zip(self.nr4, self.a4, self.b4, self.A, - self.B, self.C, self.D, self.beta4): - Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) - F = exp(-C*(delta-1)**2-D*(tau-1)**2) - Ft = -2*D*F*(tau-1) - Delta = Tita**2+B*((delta-1)**2)**a - DeltaBt = -2*Tita*b*Delta**(b-1) - firt += n*delta*(DeltaBt*F+Delta**b*Ft) - - return firt - - def helmholtz(self, tau: float, delta: float) -> HelmholtzDerivatives: - """Residual contribution to the free Helmholtz energy - - Parameters - ---------- - tau : float - Inverse reduced temperature Tc/T, [-] - delta : float - Reduced density rho/rhoc, [-] - - Returns - ------- - HelmholtzDerivatives class, with residual adimensional helmholtz - energy and deriv: - * fir - * firt: ∂fir/∂τ|δ,x - * fird: ∂fir/∂δ|τ,x - * firtt: ∂²fir/∂τ²|δ,x - * firdt: ∂²fir/∂τ∂δ|x - * firdd: ∂²fir/∂δ²|τ,x - - References - ---------- - IAPWS, Revised Release on the IAPWS Formulation 1995 for the - Thermodynamic Properties of Ordinary Water Substance for General and - Scientific Use, September 2016, Table 5 - http://www.iapws.org/relguide/IAPWS-95.html - """ - # Ensure parameters are really floats. - tau = float(tau) - delta = float(delta) - - fir = fird = firdd = firt = firtt = firdt = 0.0 - # Polinomial terms - for n, d, t in zip(self.nr1, self.d1, self.t1): - fir += n*delta**d*tau**t - fird += n*d*delta**(d-1)*tau**t - firdd += n*d*(d-1)*delta**(d-2)*tau**t - firt += n*t*delta**d*tau**(t-1) - firtt += n*t*(t-1)*delta**d*tau**(t-2) - firdt += n*t*d*delta**(d-1)*tau**(t-1) - - # Exponential terms - failed = False - for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): - try: - expgdc = exp(-g*delta**c) - except OverflowError: - failed = True - expgdc = float('inf') - fir += n*delta**d*tau**t*expgdc - fird += n*expgdc*delta**(d-1)*tau**t*(d-g*c*delta**c) - firdd += n*expgdc*delta**(d-2)*tau**t * \ - ((d-g*c*delta**c)*(d-1-g*c*delta**c)-g**2*c**2*delta**c) - firt += n*t*delta**d*tau**(t-1)*expgdc - firtt += n*t*(t-1)*delta**d*tau**(t-2)*expgdc - firdt += n*t*delta**(d-1)*tau**(t-1)*(d-g*c*delta**c)*expgdc - if failed: - fir = float('nan') - - # Gaussian terms - for n, d, t, a, e, b, g in zip(self.nr3, self.d3, self.t3, self.alfa3, - self.epsilon3, self.beta3, self.gamma3): - fir += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2) - fird += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - d/delta-2*a*(delta-e)) - firdd += n*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - -2*a*delta**d + 4*a**2*delta**d*(delta-e)**2 - - 4*d*a*delta**(d-1)*(delta-e) + d*(d-1)*delta**(d-2)) - firt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - t/tau-2*b*(tau-g)) - firtt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - (t/tau-2*b*(tau-g))**2-t/tau**2-2*b) - firdt += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - t/tau-2*b*(tau-g))*(d/delta-2*a*(delta-e)) - - # Non analitic terms - for n, a, b, A, B, C, D, bt in zip(self.nr4, self.a4, self.b4, self.A, - self.B, self.C, self.D, self.beta4): - Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) - F = exp(-C*(delta-1)**2-D*(tau-1)**2) - Fd = -2*C*F*(delta-1) - Fdd = 2*C*F*(2*C*(delta-1)**2-1) - Ft = -2*D*F*(tau-1) - Ftt = 2*D*F*(2*D*(tau-1)**2-1) - Fdt = 4*C*D*F*(delta-1)*(tau-1) - - Delta = Tita**2+B*((delta-1)**2)**a - Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**(0.5/bt-1) - + 2*B*a*((delta-1)**2)**(a-1)) - if delta == 1: - Deltadd = 0 - else: - Deltadd = Deltad/(delta-1)+(delta-1)**2*( - 4*B*a*(a-1)*((delta-1)**2)**(a-2) - + 2*A**2/bt**2*(((delta-1)**2)**(0.5/bt-1))**2 - + A*Tita*4/bt*(0.5/bt-1)*((delta-1)**2)**(0.5/bt-2)) - - DeltaBd = b*Delta**(b-1)*Deltad - DeltaBdd = b*(Delta**(b-1)*Deltadd+(b-1)*Delta**(b-2)*Deltad**2) - DeltaBt = -2*Tita*b*Delta**(b-1) - DeltaBtt = 2*b*Delta**(b-1)+4*Tita**2*b*(b-1)*Delta**(b-2) - DeltaBdt = -A*b*2/bt*Delta**(b-1)*(delta-1)*((delta-1)**2)**( - 0.5/bt-1)-2*Tita*b*(b-1)*Delta**(b-2)*Deltad - - fir += n*Delta**b*delta*F - fird += n*(Delta**b*(F+delta*Fd)+DeltaBd*delta*F) - firdd += n*(Delta**b*(2*Fd+delta*Fdd) + 2*DeltaBd*(F+delta*Fd) - + DeltaBdd*delta*F) - firt += n*delta*(DeltaBt*F+Delta**b*Ft) - firtt += n*delta*(DeltaBtt*F+2*DeltaBt*Ft+Delta**b*Ftt) - firdt += n*(Delta**b*(Ft+delta*Fdt)+delta*DeltaBd*Ft - + DeltaBt*(F+delta*Fd)+DeltaBdt*delta*F) - - return HelmholtzDerivatives(fir, firt, fird, firtt, firdd, firdt) - - def _virial(self, T: float, Tc: float) -> Dict[str, float]: - """Virial coefficient - - Parameters - ---------- - T : float - Temperature [K] - - Returns - ------- - prop : dict - Dictionary with residual adimensional helmholtz energy: - * B: ∂fir/∂δ|δ->0 - * C: ∂²fir/∂δ²|δ->0 - """ - tau = Tc/T - B = C = 0.0 - delta = 1e-200 - - # Polinomial terms - for n, d, t in zip(self.nr1, self.d1, self.t1): - B += n*d*delta**(d-1)*tau**t - C += n*d*(d-1)*delta**(d-2)*tau**t - - # Exponential terms - for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): - B += n*exp(-g*delta**c)*delta**(d-1)*tau**t*(d-g*c*delta**c) - C += n*exp(-g*delta**c)*(delta**(d-2)*tau**t*( - (d-g*c*delta**c)*(d-1-g*c*delta**c)-g**2*c**2*delta**c)) - - # Gaussian terms - for n, d, t, a, e, b, g in zip(self.nr3, self.d3, self.t3, self.alfa3, - self.epsilon3, self.beta3, self.gamma3): - B += n*delta**d*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - d/delta-2*a*(delta-e)) - C += n*tau**t*exp(-a*(delta-e)**2-b*(tau-g)**2)*( - -2*a*delta**d+4*a**2*delta**d*( - delta-e)**2-4*d*a*delta**2*( - delta-e)+d*2*delta) - - # Non analitic terms - for n, a, b, A, B_, C_, D, bt in zip(self.nr4, self.a4, self.b4, self.A, - self.B, self.C, self.D, self.beta4): - Tita = (1-tau)+A*((delta-1)**2)**(0.5/bt) - Delta = Tita**2+B_*((delta-1)**2)**a - Deltad = (delta-1)*(A*Tita*2/bt*((delta-1)**2)**( - 0.5/bt-1)+2*B_*a*((delta-1)**2)**(a-1)) - Deltadd = Deltad/(delta-1) + (delta-1)**2*( - 4*B_*a*(a-1)*((delta-1)**2)**(a-2) - + 2*A**2/bt**2*(((delta-1)**2)**(0.5/bt-1))**2 - + A*Tita*4/bt*(0.5/bt-1)*((delta-1)**2)**(0.5/bt-2)) - DeltaBd = b*Delta**(b-1)*Deltad - DeltaBdd = b*(Delta**(b-1)*Deltadd+(b-1)*Delta**(b-2)*Deltad**2) - F = exp(-C_*(delta-1)**2-D*(tau-1)**2) - Fd = -2*C_*F*(delta-1) - Fdd = 2*C_*F*(2*C_*(delta-1)**2-1) - - B += n*(Delta**b*(F+delta*Fd)+DeltaBd*delta*F) - C += n*(Delta**b*(2*Fd+delta*Fdd)+2*DeltaBd*(F+delta*Fd) - + DeltaBdd*delta*F) - - prop = {} - prop["B"] = B - prop["C"] = C - return prop +from ._utils import _fase, getphase, deriv_H +from .helmholtz import ResidualContribution, HelmholtzDerivatives class MEoSProperties(object): From 5822206f842b242d702dab4e67078b5c39504578 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Fri, 19 Mar 2021 21:24:14 -0400 Subject: [PATCH 096/102] Remove gamma2, since it's always just ones. Maybe there's a "traditional form" of these equations or something like that where seeing the gamma2 terms makes them more familar. To me is was just additional unnecessary complexity. --- iapws/ammonia.py | 1 - iapws/helmholtz.py | 54 ++++++++++++++++++++++------------------------ iapws/humidAir.py | 1 - iapws/iapws95.py | 2 -- 4 files changed, 26 insertions(+), 32 deletions(-) diff --git a/iapws/ammonia.py b/iapws/ammonia.py index dba6a66..905ecd2 100644 --- a/iapws/ammonia.py +++ b/iapws/ammonia.py @@ -69,7 +69,6 @@ class NH3(MEoS): d2=[3, 3, 1, 8, 2, 8, 1, 1, 2, 3, 2, 4, 3, 1, 2, 4], t2=[0, 3, 4, 4, 5, 5, 3, 6, 8, 8, 10, 10, 5, 7.5, 15, 30], c2=[1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3], - gamma2=[1]*16, nr3=[], d3=[], t3=[], alfa3=[], beta3=[], gamma3=[], epsilon3=[], nr4=[], a4=[], b4=[], A=[], B=[], C=[], D=[], beta4=[], diff --git a/iapws/helmholtz.py b/iapws/helmholtz.py index db13379..70dcfe0 100644 --- a/iapws/helmholtz.py +++ b/iapws/helmholtz.py @@ -23,12 +23,11 @@ class ResidualContribution(object): """Residual contribution to the adimensional free Helmholtz energy""" def __init__(self, nr1: List[float], d1: List[float], t1: List[float], - nr2: List[float], d2: List[float], gamma2: List[int], - t2: List[float], c2: List[int], nr3: List[float], - d3: List[int], t3: List[float], alfa3: List[float], - epsilon3: List[float], beta3: List[float], gamma3: List[float], - nr4: List[float], a4: List[float], b4: List[float], - A: List[float], B: List[float], C: List[int], + nr2: List[float], d2: List[float], t2: List[float], + c2: List[int], nr3: List[float], d3: List[int], t3: List[float], + alfa3: List[float], epsilon3: List[float], beta3: List[float], + gamma3: List[float], nr4: List[float], a4: List[float], + b4: List[float], A: List[float], B: List[float], C: List[int], D: List[int], beta4: List[float]) -> None: # Polinomial terms self.nr1 = nr1 @@ -37,7 +36,6 @@ def __init__(self, nr1: List[float], d1: List[float], t1: List[float], # Exponential terms self.nr2 = nr2 self.d2 = d2 - self.gamma2 = gamma2 # Gamma2 is always ones? self.t2 = t2 self.c2 = c2 # Gaussian terms (optional, may be empty lists) @@ -92,8 +90,8 @@ def phir(self, tau: float, delta: float) -> float: fir += n*delta**d*tau**t # Exponential terms - for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): - fir += n*delta**d*tau**t*exp(-g*delta**c) + for n, d, t, c in zip(self.nr2, self.d2, self.t2, self.c2): + fir += n*delta**d*tau**t*exp(-delta**c) # Gaussian terms for n, d, t, a, e, b, g in zip(self.nr3, self.d3, self.t3, self.alfa3, @@ -146,13 +144,13 @@ def phird(self, tau: float, delta: float) -> float: fird += n*d*delta**(d-1)*tau**t # Exponential terms - for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): + for n, d, t, c in zip(self.nr2, self.d2, self.t2, self.c2): try: - expt = exp(-g*delta**c) + expt = exp(-delta**c) except OverflowError: fird = float('nan') break - fird += n*expt*delta**(d-1)*tau**t*(d-g*c*delta**c) + fird += n*expt*delta**(d-1)*tau**t*(d-c*delta**c) # Gaussian terms for n, d, t, a, e, b, g in zip(self.nr3, self.d3, self.t3, self.alfa3, @@ -212,8 +210,8 @@ def phirt(self, tau: float, delta: float) -> float: firt += n*t*delta**d*tau**(t-1) # Exponential terms - for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): - firt += n*t*delta**d*tau**(t-1)*exp(-g*delta**c) + for n, d, t, c in zip(self.nr2, self.d2, self.t2, self.c2): + firt += n*t*delta**d*tau**(t-1)*exp(-delta**c) # Gaussian terms for n, d, t, a, e, b, g in zip(self.nr3, self.d3, self.t3, self.alfa3, @@ -277,19 +275,19 @@ def helmholtz(self, tau: float, delta: float) -> HelmholtzDerivatives: # Exponential terms failed = False - for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): + for n, d, t, c in zip(self.nr2, self.d2, self.t2, self.c2): try: - expgdc = exp(-g*delta**c) + expdc = exp(-delta**c) except OverflowError: failed = True - expgdc = float('inf') - fir += n*delta**d*tau**t*expgdc - fird += n*expgdc*delta**(d-1)*tau**t*(d-g*c*delta**c) - firdd += n*expgdc*delta**(d-2)*tau**t * \ - ((d-g*c*delta**c)*(d-1-g*c*delta**c)-g**2*c**2*delta**c) - firt += n*t*delta**d*tau**(t-1)*expgdc - firtt += n*t*(t-1)*delta**d*tau**(t-2)*expgdc - firdt += n*t*delta**(d-1)*tau**(t-1)*(d-g*c*delta**c)*expgdc + expdc = float('inf') + fir += n*delta**d*tau**t*expdc + fird += n*expdc*delta**(d-1)*tau**t*(d-c*delta**c) + firdd += n*expdc*delta**(d-2)*tau**t * \ + ((d-c*delta**c)*(d-1-c*delta**c)-c**2*delta**c) + firt += n*t*delta**d*tau**(t-1)*expdc + firtt += n*t*(t-1)*delta**d*tau**(t-2)*expdc + firdt += n*t*delta**(d-1)*tau**(t-1)*(d-c*delta**c)*expdc if failed: fir = float('nan') @@ -374,10 +372,10 @@ def _virial(self, T: float, Tc: float) -> Dict[str, float]: C += n*d*(d-1)*delta**(d-2)*tau**t # Exponential terms - for n, d, g, t, c in zip(self.nr2, self.d2, self.gamma2, self.t2, self.c2): - B += n*exp(-g*delta**c)*delta**(d-1)*tau**t*(d-g*c*delta**c) - C += n*exp(-g*delta**c)*(delta**(d-2)*tau**t*( - (d-g*c*delta**c)*(d-1-g*c*delta**c)-g**2*c**2*delta**c)) + for n, d, t, c in zip(self.nr2, self.d2, self.t2, self.c2): + B += n*exp(-delta**c)*delta**(d-1)*tau**t*(d-c*delta**c) + C += n*exp(-delta**c)*(delta**(d-2)*tau**t*( + (d-c*delta**c)*(d-1-c*delta**c)-c**2*delta**c)) # Gaussian terms for n, d, t, a, e, b, g in zip(self.nr3, self.d3, self.t3, self.alfa3, diff --git a/iapws/humidAir.py b/iapws/humidAir.py index 4ec68b9..5b2c1c3 100644 --- a/iapws/humidAir.py +++ b/iapws/humidAir.py @@ -317,7 +317,6 @@ class Air(MEoSBlend): d2=[1, 3, 5, 6, 1, 3, 11, 1, 3], t2=[1.6, 0.8, 0.95, 1.25, 3.6, 6, 3.25, 3.5, 15], c2=[1, 1, 1, 1, 2, 2, 2, 3, 3], - gamma2=[1]*9, nr3=[], d3=[], t3=[], alfa3=[], beta3=[], gamma3=[], epsilon3=[], nr4=[], a4=[], b4=[], A=[], B=[], C=[], D=[], beta4=[], diff --git a/iapws/iapws95.py b/iapws/iapws95.py index ddabf82..8c126aa 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -1980,7 +1980,6 @@ class IAPWS95(MEoS): t2=[4, 6, 12, 1, 5, 4, 2, 13, 9, 3, 4, 11, 4, 13, 1, 7, 1, 9, 10, 10, 3, 7, 10, 10, 6, 10, 10, 1, 2, 3, 4, 8, 6, 9, 8, 16, 22, 23, 23, 10, 50, 44, 46, 50], - gamma2=[1]*44, nr3=[-0.31306260323435e2, 0.31546140237781e2, -0.25213154341695e4], d3=[3]*3, @@ -2312,7 +2311,6 @@ class D2O(MEoS): c2=[1, 2, 2, 1, 2, 2], d2=[1, 1, 3, 2, 2, 1], t2=[3.9515, 4.6000, 5.1590, 0.2000, 5.4644, 2.3660], - gamma2=[1]*6, nr3=[-0.456110600e-1, -0.224513300e1, 0.860006070e1, -0.248410420e1, 0.164476900e2, 0.270393360e1, 0.375637470e2, -0.177607760e1, From 0cde2a5197539c24552fc14a1e19546b1d648bde Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 20 Mar 2021 12:56:03 -0400 Subject: [PATCH 097/102] Split up the thousand line calculo function. The size of this function was one of the primary reasons that I started making changes to IAPWS. While I understood the overall structure of this function, I was unable to understand what the inputs and output of each calculation "mode" was because everything was in a single scope with processing before and processing after the "switch". This version is far from perfect, and is about 150 lines larger than the previous version, but I think it's a lot more readable, and it's likely that the size will return to something more like the orginal after some additional cleanup, but this seemed like a good place to commit. --- iapws/iapws95.py | 1902 +++++++++++++++++++++++++--------------------- 1 file changed, 1024 insertions(+), 878 deletions(-) diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 8c126aa..99f27d9 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -311,20 +311,14 @@ def calculable(self) -> bool: self._mode = "Px" return bool(self._mode) - def calculo(self) -> None: - """Calculate procedure""" - T: float = self.kwargs["T"] # type: ignore - rho: float = self.kwargs["rho"] # type: ignore - P: float = self.kwargs["P"] # type: ignore - s: float = self.kwargs["s"] # type: ignore - h: float = self.kwargs["h"] # type: ignore - u: float = self.kwargs["u"] # type: ignore - x: float = self.kwargs["x"] # type: ignore - + def get_To_rhoo_x0(self, T0: Optional[float], + rho0: Optional[float]) -> Tuple[float, float, Optional[float]]: + """Compute three values from kwargs.""" # Initial values T0 = self.kwargs["T0"] rho0 = self.kwargs["rho0"] + x0: Optional[float] = None if T0 or rho0: if T0 is not None: To = float(T0) @@ -343,892 +337,1050 @@ def calculo(self) -> None: if st0.status: To = st0.T rhoo = st0.rho + x0 = st0.x else: To = 300 rhoo = 900 + return(To, rhoo, x0) - self.R = self._constant_R/self.M - rhoc = self._constant_rhoc - Tc = self._constant_Tref + def calculo(self) -> None: + """Calculate procedure""" + T: float = self.kwargs["T"] # type: ignore + rho: float = self.kwargs["rho"] # type: ignore + P: float = self.kwargs["P"] # type: ignore + s: float = self.kwargs["s"] # type: ignore + h: float = self.kwargs["h"] # type: ignore + u: float = self.kwargs["u"] # type: ignore + x: float = self.kwargs["x"] # type: ignore - if self._mode not in ("Tx", "Px"): - # Method with iteration necessary to get x - if self._mode == "TP": - try: - if self.name != "water": - raise NotImplementedError - st0 = IAPWS97(**self.kwargs) - rhoo = st0.rho - except NotImplementedError: - if rho0: - rhoo = rho0 - elif T < self._constant_Tref and P < self.Pc and \ - self._Vapor_Pressure(T) < P: - rhoo = self._Liquid_Density(T) - elif T < self._constant_Tref and P < self.Pc: - rhoo = self._Vapor_Density(T) - else: - rhoo = self._constant_rhoc*3 - - def rho_func(rho: float) -> float: - delta = rho/rhoc - tau = Tc/T - - fird = self.residual.phird(tau, delta) - Po = (1+delta*fird)*self.R*T*rho - return Po-P*1000 + T0 = self.kwargs["T0"] + rho0 = self.kwargs["rho0"] + To, rhoo, x0 = self.get_To_rhoo_x0(T0, rho0) + + # Method with iteration necessary to get x + if self._mode == "TP": + self.solve_T_P(T, P, rho0, rhoo) + elif self._mode == "Th": + self.solve_T_h(T, h) + elif self._mode == "Ts": + self.solve_T_s(T, s) + elif self._mode == "Tu": + self.solve_T_u(T, u) + elif self._mode == "Prho": + self.solve_P_rho(P, rho, To) + elif self._mode == "Ph": + self.solve_P_h(P, h, rhoo, To) + elif self._mode == "Ps": + self.solve_P_s(P, s, rhoo, To, x0) + elif self._mode == "Pu": + self.solve_P_u(P, u, rhoo, To) + elif self._mode == "rhoh": + self.solve_rho_h(rho, h, To) + elif self._mode == "rhos": + self.solve_rho_s(rho, s, To) + elif self._mode == "rhou": + self.solve_rho_u(rho, u, rhoo, To) + elif self._mode == "hs": + self.solve_h_s(h, s, rhoo, To) + elif self._mode == "hu": + self.solve_h_u(h, u, rhoo, To) + elif self._mode == "su": + self.solve_s_u(s, u, rhoo, To) + elif self._mode == "Trho": + self.solve_T_rho(T, rho) + elif self._mode == "Tx": + self.solve_T_x(T, x) + elif self._mode == "Px": + self.solve_P_x(P, x, T0) - rho = float(fsolve(rho_func, rhoo)[0]) + def solve_T_P(self, T: float, P: float, + rho0: Optional[float], rhoo: float) -> None: + """Solve for properties using T & P.""" + try: + if self.name != "water": + raise NotImplementedError + st0 = IAPWS97(**self.kwargs) + rhoo = st0.rho + except NotImplementedError: + if rho0: + rhoo = rho0 + elif T < self._constant_Tref and P < self.Pc and \ + self._Vapor_Pressure(T) < P: + rhoo = self._Liquid_Density(T) + elif T < self._constant_Tref and P < self.Pc: + rhoo = self._Vapor_Density(T) + else: + rhoo = self._constant_rhoc*3 - # Calculate quality - if T > self._constant_Tref: - x = 1 - else: - Ps = self._Vapor_Pressure(T) - if Ps*0.95 < P < Ps*1.05: - rhol, rhov, Ps = self._saturation(T) - Ps *= 1e-3 - - if Ps > P: - x = 1 - else: - x = 0 - - elif self._mode == "Th": - tau = Tc/T - ideal = self._phi0(tau, 1) - fiot = ideal.fit - - def rho_func(rho: float) -> float: - delta = rho/rhoc - fird = self.residual.phird(tau, delta) - firt = self.residual.phirt(tau, delta) - ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) - return ho-h - - if T >= self._constant_Tref: - rhoo = self._constant_rhoc - rho = float(fsolve(rho_func, rhoo)[0]) - else: - x0 = self.kwargs["x0"] - rhov = self._Vapor_Density(T) - rhol = self._Liquid_Density(T) - deltaL = rhol/rhoc - deltaG = rhov/rhoc - - firdL = self.residual.phird(tau, deltaL) - firtL = self.residual.phirt(tau, deltaL) - firdG = self.residual.phird(tau, deltaG) - firtG = self.residual.phirt(tau, deltaG) - hl = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) - hv = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) - if x0 not in (0, 1) and hl <= h <= hv: - rhol, rhov, Ps = self._saturation(T) - vapor = self._Helmholtz(rhov, T) - liquido = self._Helmholtz(rhol, T) - hv = vapor.h - hl = liquido.h - x = (h-hl)/(hv-hl) - rho = 1/(x/rhov+(1-x)/rhol) - P = Ps/1000 - else: - if h > hv: - rhoo = rhov - else: - rhoo = rhol - rho = float(fsolve(rho_func, rhoo)[0]) - - elif self._mode == "Ts": - tau = Tc/T - - def rho_func(rho: float) -> float: - if rho < 0: - rho = 1e-20 - delta = rho/rhoc - - ideal = self._phi0(tau, delta) - fir = self.residual.phir(tau, delta) - firt = self.residual.phirt(tau, delta) - so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) - return so-s - - if T >= self._constant_Tref: - rhoo = self._constant_rhoc - rho = float(fsolve(rho_func, rhoo)[0]) + def rho_func(rho: float) -> float: + delta = rho/self._constant_rhoc + tau = self._constant_Tref/T + + fird = self.residual.phird(tau, delta) + Po = (1+delta*fird)*self.R*T*rho + return Po-P*1000 + + rho = float(fsolve(rho_func, rhoo)[0]) + + # Calculate quality + if T > self._constant_Tref: + x = 1.0 + else: + Ps = self._Vapor_Pressure(T) + if Ps*0.95 < P < Ps*1.05: + rhol, rhov, Ps = self._saturation(T) + Ps *= 1e-3 + + if Ps > P: + x = 1.0 + else: + x = 0.0 + + self.solve_case1(T, P, x, rho, None, None) + + def solve_T_h(self, T: float, h: float) -> None: + """Solve for properties using T & h.""" + tau = self._constant_Tref/T + ideal = self._phi0(tau, 1) + fiot = ideal.fit + x = None + P = 0.0 + + def rho_func(rho: float) -> float: + delta = rho/self._constant_rhoc + fird = self.residual.phird(tau, delta) + firt = self.residual.phirt(tau, delta) + ho = self.R*T*(1+tau*(fiot+firt)+delta*fird) + return ho-h + + liquido = None + vapor = None + if T >= self._constant_Tref: + rhoo = self._constant_rhoc + rho = float(fsolve(rho_func, rhoo)[0]) + else: + x0 = self.kwargs["x0"] + rhov = self._Vapor_Density(T) + rhol = self._Liquid_Density(T) + deltaL = rhol/self._constant_rhoc + deltaG = rhov/self._constant_rhoc + + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) + hl = self.R*T*(1+tau*(fiot+firtL)+deltaL*firdL) + hv = self.R*T*(1+tau*(fiot+firtG)+deltaG*firdG) + if x0 not in (0, 1) and hl <= h <= hv: + rhol, rhov, Ps = self._saturation(T) + vapor = self._Helmholtz(rhov, T) + liquido = self._Helmholtz(rhol, T) + hv = vapor.h + hl = liquido.h + x = (h-hl)/(hv-hl) + rho = 1/(x/rhov+(1-x)/rhol) + P = Ps/1000 + else: + if h > hv: + rhoo = rhov else: - rhov = self._Vapor_Density(T) - rhol = self._Liquid_Density(T) - deltaL = rhol/rhoc - deltaG = rhov/rhoc - - idealL = self._phi0(tau, deltaL) - idealG = self._phi0(tau, deltaG) - - firL = self.residual.phir(tau, deltaL) - firtL = self.residual.phirt(tau, deltaL) - sl = self.R*(tau*(idealL.fit+firtL)-idealL.fi-firL) - firG = self.residual.phir(tau, deltaG) - firtG = self.residual.phirt(tau, deltaG) - sv = self.R*(tau*(idealL.fit+firtG)-idealG.fi-firG) - - if sl <= s <= sv: - rhol, rhov, Ps = self._saturation(T) - vapor = self._Helmholtz(rhov, T) - liquido = self._Helmholtz(rhol, T) - sv = vapor.s - sl = liquido.s - x = (s-sl)/(sv-sl) - rho = 1/(x/rhov+(1-x)/rhol) - P = Ps/1000 - else: - if s > sv: - rhoo = rhov - else: - rhoo = rhol - rho = float(fsolve(rho_func, rhoo)[0]) - - elif self._mode == "Tu": - tau = Tc/T - ideal = self._phi0(tau, 1) - - def rho_func(rho: float) -> float: - delta = rho/rhoc - - fird = self.residual.phird(tau, delta) - firt = self.residual.phirt(tau, delta) - Po = (1+delta*fird)*self.R*T*rho - ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) - - return ho-Po/rho-u - - if T >= self._constant_Tref: - rhoo = self._constant_rhoc - rho = float(fsolve(rho_func, rhoo)[0]) + rhoo = rhol + rho = float(fsolve(rho_func, rhoo)[0]) + + self.solve_case1(T, P, x, rho, liquido, vapor) + + def solve_T_s(self, T: float, s: float) -> None: + """Solve for properties using T & s.""" + tau = self._constant_Tref/T + x = None + P = 0.0 + + def rho_func(rho: float) -> float: + if rho < 0: + rho = 1e-20 + delta = rho/rhoc + + ideal = self._phi0(tau, delta) + fir = self.residual.phir(tau, delta) + firt = self.residual.phirt(tau, delta) + so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) + return so-s + + liquido = None + vapor = None + if T >= self._constant_Tref: + rhoo = self._constant_rhoc + rho = float(fsolve(rho_func, rhoo)[0]) + else: + rhov = self._Vapor_Density(T) + rhol = self._Liquid_Density(T) + deltaL = rhol/self._constant_rhoc + deltaG = rhov/self._constant_rhoc + + idealL = self._phi0(tau, deltaL) + idealG = self._phi0(tau, deltaG) + + firL = self.residual.phir(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) + sl = self.R*(tau*(idealL.fit+firtL)-idealL.fi-firL) + firG = self.residual.phir(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) + sv = self.R*(tau*(idealL.fit+firtG)-idealG.fi-firG) + + if sl <= s <= sv: + rhol, rhov, Ps = self._saturation(T) + vapor = self._Helmholtz(rhov, T) + liquido = self._Helmholtz(rhol, T) + sv = vapor.s + sl = liquido.s + x = (s-sl)/(sv-sl) + rho = 1/(x/rhov+(1-x)/rhol) + P = Ps/1000 + else: + if s > sv: + rhoo = rhov else: - rhov = self._Vapor_Density(T) - rhol = self._Liquid_Density(T) - deltaL = rhol/rhoc - deltaG = rhov/rhoc - - firdL = self.residual.phird(tau, deltaL) - firtL = self.residual.phirt(tau, deltaL) - firdG = self.residual.phird(tau, deltaG) - firtG = self.residual.phirt(tau, deltaG) - PoL = (1+deltaL*firdL)*self.R*T*rhol - PoG = (1+deltaG*firdG)*self.R*T*rhov - hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) - hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) - - uv = hoG-PoG/rhov - ul = hoL-PoL/rhol - if ul <= u <= uv: - rhol, rhov, Ps = self._saturation(T) - vapor = self._Helmholtz(rhov, T) - liquido = self._Helmholtz(rhol, T) - uv = vapor.h-vapor.P/rhov - ul = liquido.h-liquido.P/rhol - x = (u-ul)/(uv-ul) - rho = 1/(x/rhov-(1-x)/rhol) - P = Ps/1000 - else: - if u > uv: - rhoo = rhov - else: - rhoo = rhol - rho = float(fsolve(rho_func, rhoo)[0]) - - elif self._mode == "Prho": - delta = rho/rhoc + rhoo = rhol + rho = float(fsolve(rho_func, rhoo)[0]) - def t_func(T: float) -> float: - tau = Tc/T - - fird = self.residual.phird(tau, delta) - Po = (1+delta*fird)*self.R*T*rho - return Po-P*1000 - - T = float(fsolve(t_func, To)[0]) - rhol = self._Liquid_Density(T) - rhov = self._Vapor_Density(T) - if T == To or rhov <= rho <= rhol: - - def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: - T, rhol, rhog = parr - tau = Tc/T - deltaL = rhol/self._constant_rhoc - deltaG = rhog/self._constant_rhoc - - firL = self.residual.phir(tau, deltaL) - firdL = self.residual.phird(tau, deltaL) - firG = self.residual.phir(tau, deltaG) - firdG = self.residual.phird(tau, deltaG) - - Jl = rhol*(1+deltaL*firdL) - Jv = rhog*(1+deltaG*firdG) - K = firL-firG - try: - logrho = log(rhol/rhog) - except ValueError: - logrho = float('nan') - Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+logrho) - return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, Ps - P*1000) - - for to in [To, 300, 400, 500, 600]: - rhoLo = self._Liquid_Density(to) - rhoGo = self._Vapor_Density(to) - sol = fsolve(f3, [to, rhoLo, rhoGo], full_output=True) - T, rhoL, rhoG = tuple(map(float, sol[0])) - x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) - if sol[2] == 1 and 0 <= x <= 1 and \ - sum(abs(sol[1]["fvec"])) < 1e-5: - break - - if sum(abs(sol[1]["fvec"])) > 1e-5: - raise(RuntimeError(sol[3])) - - liquido = self._Helmholtz(rhoL, T) - vapor = self._Helmholtz(rhoG, T) - P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( - liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 - - elif self._mode == "Ph": - def f2(parr: Tuple[float, float]) -> Tuple[float, float]: - rho, T = parr - delta = rho/rhoc - tau = Tc/T - - ideal = self._phi0(tau, delta) - fird = self.residual.phird(tau, delta) - firt = self.residual.phirt(tau, delta) - Po = (1+delta*fird)*self.R*T*rho - ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) - return Po-P*1000, ho-h - - rho, T = tuple(map(float, fsolve(f2, [rhoo, To]))) - rhol = self._Liquid_Density(T) - rhov = self._Vapor_Density(T) - if rho == rhoo or rhov <= rho <= rhol: - - def f4(parr: Tuple[float, float, float, float]) -> Tuple[ - float, float, float, float]: - T, rhol, rhog, x = parr - tau = Tc/T - deltaL = rhol/self._constant_rhoc - deltaG = rhog/self._constant_rhoc - - ideal = self._phi0(tau, deltaL) - - firL = self.residual.phir(tau, deltaL) - firdL = self.residual.phird(tau, deltaL) - firtL = self.residual.phirt(tau, deltaL) - hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) - firG = self.residual.phir(tau, deltaG) - firdG = self.residual.phird(tau, deltaG) - firtG = self.residual.phirt(tau, deltaG) - hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) - - Jl = rhol*(1+deltaL*firdL) - Jv = rhog*(1+deltaG*firdG) - K = firL-firG - Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) - - return (Jl-Jv, - Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, - hoL*(1-x)+hoG*x - h, - Ps - P*1000) - - for to in [To, 300, 400, 500, 600]: - rLo = self._Liquid_Density(to) - rGo = self._Vapor_Density(to) - sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) - T, rhoL, rhoG, x = tuple(map(float, sol[0])) - if sol[2] == 1 and 0 <= x <= 1 and \ - sum(abs(sol[1]["fvec"])) < 1e-5: - break - - if sum(abs(sol[1]["fvec"])) > 1e-5: - raise(RuntimeError(sol[3])) - - liquido = self._Helmholtz(rhoL, T) - vapor = self._Helmholtz(rhoG, T) - P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( - liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 - - elif self._mode == "Ps": - try: - x0 = st0.x - except NameError: - x0 = None + self.solve_case1(T, P, x, rho, liquido, vapor) + + def solve_T_u(self, T: float, u: float) -> None: + """Solve for properties using T & u.""" + tau = self._constant_Tref/T + ideal = self._phi0(tau, 1) + x = None + P = 0.0 - if x0 is None or x0 == 0 or x0 == 1: - def f2(parr: Tuple[float, float]) -> Tuple[float, float]: - rho, T = parr - delta = rho/rhoc - tau = Tc/T + def rho_func(rho: float) -> float: + delta = rho/self._constant_rhoc - ideal = self._phi0(tau, delta) - fird = self.residual.phird(tau, delta) - fir = self.residual.phir(tau, delta) - firt = self.residual.phirt(tau, delta) - Po = (1+delta*fird)*self.R*T*rho - so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) - return Po-P*1000, so-s + fird = self.residual.phird(tau, delta) + firt = self.residual.phirt(tau, delta) + Po = (1+delta*fird)*self.R*T*rho + ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) - rho, T = tuple(map(float, fsolve(f2, [rhoo, To]))) + return ho-Po/rho-u + liquido = None + vapor = None + if T >= self._constant_Tref: + rhoo = self._constant_rhoc + rho = float(fsolve(rho_func, rhoo)[0]) + else: + rhov = self._Vapor_Density(T) + rhol = self._Liquid_Density(T) + deltaL = rhol/self._constant_rhoc + deltaG = rhov/self._constant_rhoc + + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) + PoL = (1+deltaL*firdL)*self.R*T*rhol + PoG = (1+deltaG*firdG)*self.R*T*rhov + hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) + hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) + + uv = hoG-PoG/rhov + ul = hoL-PoL/rhol + if ul <= u <= uv: + rhol, rhov, Ps = self._saturation(T) + vapor = self._Helmholtz(rhov, T) + liquido = self._Helmholtz(rhol, T) + uv = vapor.h-vapor.P/rhov + ul = liquido.h-liquido.P/rhol + x = (u-ul)/(uv-ul) + rho = 1/(x/rhov-(1-x)/rhol) + P = Ps/1000 + else: + if u > uv: + rhoo = rhov else: - def f2(parr: Tuple[float, float]) -> Tuple[float, float]: - rho, T = parr - rhol, rhov, Ps = self._saturation(T) - vapor = self._Helmholtz(rhov, T) - liquido = self._Helmholtz(rhol, T) - x = (1./rho-1/rhol)/(1/rhov-1/rhol) - return Ps-P*1000, vapor.s*x+liquido.s*(1-x)-s - rho, T = tuple(map(float, fsolve(f2, [2., 500.]))) - rhol, rhov, Ps = self._saturation(T) - vapor = self._Helmholtz(rhov, T) - liquido = self._Helmholtz(rhol, T) - sv = vapor.s - sl = liquido.s - x = (s-sl)/(sv-sl) - - elif self._mode == "Pu": - def f2(parr: Tuple[float, float]) -> Tuple[float, float]: - rho, T = parr - delta = rho/rhoc - tau = Tc/T - - ideal = self._phi0(tau, delta) - fird = self.residual.phird(tau, delta) - firt = self.residual.phirt(tau, delta) - Po = (1+delta*fird)*self.R*T*rho - ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) - return ho-Po/rho-u, Po-P*1000 - - sol = fsolve(f2, [rhoo, To], full_output=True) - rho, T = tuple(map(float, sol[0])) - rhol = self._Liquid_Density(T) - rhov = self._Vapor_Density(T) - if rho == rhoo or sol[2] != 1: - - def f4(parr: Tuple[float, float, float, float]) -> Tuple[ - float, float, float, float]: - T, rhol, rhog, x = parr - tau = Tc/T - deltaL = rhol/self._constant_rhoc - deltaG = rhog/self._constant_rhoc - - ideal = self._phi0(tau, deltaL) - - firL = self.residual.phir(tau, deltaL) - firdL = self.residual.phird(tau, deltaL) - firtL = self.residual.phirt(tau, deltaL) - hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) - firG = self.residual.phir(tau, deltaG) - firdG = self.residual.phird(tau, deltaG) - firtG = self.residual.phirt(tau, deltaG) - hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) - - Jl = rhol*(1+deltaL*firdL) - Jv = rhog*(1+deltaG*firdG) - K = firL-firG - try: - logrho = log(rhol/rhog) - except ValueError: - logrho = float('nan') - Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+logrho) - vu = hoG-Ps/rhog - lu = hoL-Ps/rhol - return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, - lu*(1-x)+vu*x - u, Ps - P*1000) - - for to in [To, 300, 400, 500, 600]: - rLo = self._Liquid_Density(to) - rGo = self._Vapor_Density(to) - sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) - T, rhoL, rhoG, x = tuple(map(float, sol[0])) - if sol[2] == 1 and 0 <= x <= 1 and \ - sum(abs(sol[1]["fvec"])) < 1e-5: - break - - if sum(abs(sol[1]["fvec"])) > 1e-5: - raise(RuntimeError(sol[3])) - - liquido = self._Helmholtz(rhoL, T) - vapor = self._Helmholtz(rhoG, T) - P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( - liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 - - elif self._mode == "rhoh": - delta = rho/rhoc + rhoo = rhol + rho = float(fsolve(rho_func, rhoo)[0]) - def t_func(T: float) -> float: - tau = Tc/T - - ideal = self._phi0(tau, delta) - fird = self.residual.phird(tau, delta) - firt = self.residual.phirt(tau, delta) - ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) - return ho-h - - T = float(fsolve(t_func, To)[0]) - rhol = self._Liquid_Density(T) - rhov = self._Vapor_Density(T) - if T == To or rhov <= rho <= rhol: - def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: - T, rhol, rhog = parr - tau = Tc/T - deltaL = rhol/self._constant_rhoc - deltaG = rhog/self._constant_rhoc - - ideal = self._phi0(tau, deltaL) - firL = self.residual.phir(tau, deltaL) - firdL = self.residual.phird(tau, deltaL) - firtL = self.residual.phirt(tau, deltaL) - hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) - firG = self.residual.phir(tau, deltaG) - firdG = self.residual.phird(tau, deltaG) - firtG = self.residual.phirt(tau, deltaG) - hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) - - Jl = rhol*(1+deltaL*firdL) - Jv = rhog*(1+deltaG*firdG) - K = firL-firG - x = (1./rho-1/rhol)/(1/rhog-1/rhol) - try: - logrho = log(rhol/rhog) - except ValueError: - logrho = float('nan') - return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, - hoL*(1-x)+hoG*x - h) - - for to in [To, 300, 400, 500, 600]: - rhoLo = self._Liquid_Density(to) - rhoGo = self._Vapor_Density(to) - sol = fsolve(f3, [to, rhoLo, rhoGo], full_output=True) - T, rhoL, rhoG = tuple(map(float, sol[0])) - x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) - if sol[2] == 1 and 0 <= x <= 1 and \ - sum(abs(sol[1]["fvec"])) < 1e-5: - break - - if sum(abs(sol[1]["fvec"])) > 1e-5: - raise(RuntimeError(sol[3])) - - liquido = self._Helmholtz(rhoL, T) - vapor = self._Helmholtz(rhoG, T) - P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( - liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 - - elif self._mode == "rhos": - delta = rho/rhoc + self.solve_case1(T, P, x, rho, liquido, vapor) + + def solve_P_rho(self, P: float, rho: float, To: float) -> None: + """Solve for properties using P & rho.""" + delta = rho/self._constant_rhoc + x = None + + def t_func(T: float) -> float: + tau = self._constant_Tref/T + fird = self.residual.phird(tau, delta) + Po = (1+delta*fird)*self.R*T*rho + return Po-P*1000 + + T = float(fsolve(t_func, To)[0]) + rhol = self._Liquid_Density(T) + rhov = self._Vapor_Density(T) + liquido = None + vapor = None + if T == To or rhov <= rho <= rhol: + + def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: + T, rhol, rhog = parr + tau = self._constant_Tref/T + deltaL = rhol/self._constant_rhoc + deltaG = rhog/self._constant_rhoc - def t_func(T: float) -> float: - tau = Tc/T - ideal = self._phi0(tau, delta) - fir = self.residual.phir(tau, delta) - firt = self.residual.phirt(tau, delta) - so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) - return so-s - - T = float(fsolve(t_func, To)[0]) - rhol = self._Liquid_Density(T) - rhov = self._Vapor_Density(T) - if T == To or rhov <= rho <= rhol: - - def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: - T, rhol, rhog = parr - tau = Tc/T - deltaL = rhol/self._constant_rhoc - deltaG = rhog/self._constant_rhoc - - idealL = self._phi0(tau, deltaL) - idealG = self._phi0(tau, deltaG) - - firL = self.residual.phir(tau, deltaL) - firdL = self.residual.phird(tau, deltaL) - firtL = self.residual.phirt(tau, deltaL) - soL = self.R*(tau*(idealL.fit+firtL)-idealL.fi-firL) - firG = self.residual.phir(tau, deltaG) - firdG = self.residual.phird(tau, deltaG) - firtG = self.residual.phirt(tau, deltaG) - soG = self.R*(tau*(idealL.fit+firtG)-idealG.fi-firG) - - Jl = rhol*(1+deltaL*firdL) - Jv = rhog*(1+deltaG*firdG) - K = firL-firG - x = (1./rho-1/rhol)/(1/rhog-1/rhol) - try: - logrho = log(rhol/rhog) - except ValueError: - logrho = float('nan') - return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, - soL*(1-x)+soG*x - s) - - for to in [To, 300, 400, 500, 600]: - rhoLo = self._Liquid_Density(to) - rhoGo = self._Vapor_Density(to) - sol = fsolve(f3, [to, rhoLo, rhoGo], full_output=True) - T, rhoL, rhoG = tuple(map(float, sol[0])) - x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) - if sol[2] == 1 and 0 <= x <= 1 and \ - sum(abs(sol[1]["fvec"])) < 1e-5: - break - - if sum(abs(sol[1]["fvec"])) > 1e-5: - raise(RuntimeError(sol[3])) - - liquido = self._Helmholtz(rhoL, T) - vapor = self._Helmholtz(rhoG, T) - P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( - liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 - - elif self._mode == "rhou": - delta = rho/rhoc + firL = self.residual.phir(tau, deltaL) + firdL = self.residual.phird(tau, deltaL) + firG = self.residual.phir(tau, deltaG) + firdG = self.residual.phird(tau, deltaG) - def t_func(T: float) -> float: - tau = Tc/T - - ideal = self._phi0(tau, delta) - fird = self.residual.phird(tau, delta) - firt = self.residual.phirt(tau, delta) - Po = (1+delta*fird)*self.R*T*rho - ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) - return ho-Po/rho-u - - T = float(fsolve(t_func, To)[0]) - rhol = self._Liquid_Density(T) - rhov = self._Vapor_Density(T) - if T == To or rhov <= rho <= rhol: - def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: - T, rhol, rhog = parr - tau = Tc/T - deltaL = rhol/self._constant_rhoc - deltaG = rhog/self._constant_rhoc - - ideal = self._phi0(tau, deltaL) - firL = self.residual.phir(tau, deltaL) - firdL = self.residual.phird(tau, deltaL) - firtL = self.residual.phirt(tau, deltaL) - hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) - firG = self.residual.phir(tau, deltaG) - firdG = self.residual.phird(tau, deltaG) - firtG = self.residual.phirt(tau, deltaG) - hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) - - Jl = rhol*(1+deltaL*firdL) - Jv = rhog*(1+deltaG*firdG) - K = firL-firG - x = (1./rho-1/rhol)/(1/rhog-1/rhol) - try: - logrho = log(rhol/rhog) - except ValueError: - logrho = float('nan') - Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+logrho) - vu = hoG-Ps/rhog - lu = hoL-Ps/rhol - return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, - lu*(1-x)+vu*x - u) - - for to in [To, 300, 400, 500, 600]: - rhoLo = self._Liquid_Density(to) - rhoGo = self._Vapor_Density(to) - sol = fsolve(f3, [to, rhoLo, rhoGo], full_output=True) - T, rhoL, rhoG = tuple(map(float, sol[0])) - x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) - if sol[2] == 1 and 0 <= x <= 1 and \ - sum(abs(sol[1]["fvec"])) < 1e-5: - break - - if sum(abs(sol[1]["fvec"])) > 1e-5: - raise(RuntimeError(sol[3])) - - liquido = self._Helmholtz(rhoL, T) - vapor = self._Helmholtz(rhoG, T) - P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( - liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 - - elif self._mode == "hs": - def f2(parr: Tuple[float, float]) -> Tuple[float, float]: - rho, T = parr - delta = rho/rhoc - tau = Tc/T - - ideal = self._phi0(tau, delta) - fird = self.residual.phird(tau, delta) - fir = self.residual.phir(tau, delta) - firt = self.residual.phirt(tau, delta) - ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) - so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) - return ho-h, so-s - - rho, T = tuple(map(float, fsolve(f2, [rhoo, To]))) - rhol = self._Liquid_Density(T) - rhov = self._Vapor_Density(T) - if rhov <= rho <= rhol: - - def f4(parr: Tuple[float, float, float, float]) -> Tuple[ - float, float, float, float]: - T, rhol, rhog, x = parr - tau = Tc/T - deltaL = rhol/self._constant_rhoc - deltaG = rhog/self._constant_rhoc - - idealL = self._phi0(tau, deltaL) - idealG = self._phi0(tau, deltaG) - - firL = self.residual.phir(tau, deltaL) - firdL = self.residual.phird(tau, deltaL) - firtL = self.residual.phirt(tau, deltaL) - hoL = self.R*T*(1+tau*(idealL.fit+firtL)+deltaL*firdL) - soL = self.R*(tau*(idealL.fit+firtL)-idealL.fi-firL) - firG = self.residual.phir(tau, deltaG) - firdG = self.residual.phird(tau, deltaG) - firtG = self.residual.phirt(tau, deltaG) - hoG = self.R*T*(1+tau*(idealL.fit+firtG)+deltaG*firdG) - soG = self.R*(tau*(idealL.fit+firtG)-idealG.fi-firG) - - Jl = rhol*(1+deltaL*firdL) - Jv = rhog*(1+deltaG*firdG) - K = firL-firG - return (Jl-Jv, - Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, - hoL*(1-x)+hoG*x - h, - soL*(1-x)+soG*x - s) - - for to in [To, 300, 400, 500, 600]: - rLo = self._Liquid_Density(to) - rGo = self._Vapor_Density(to) - sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) - T, rhoL, rhoG, x = tuple(map(float, sol[0])) - if sol[2] == 1 and 0 <= x <= 1 and \ - sum(abs(sol[1]["fvec"])) < 1e-5: - break - - if sum(abs(sol[1]["fvec"])) > 1e-5: - raise(RuntimeError(sol[3])) - - liquido = self._Helmholtz(rhoL, T) - vapor = self._Helmholtz(rhoG, T) - P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( - liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 - - elif self._mode == "hu": - def f2(parr: Tuple[float, float]) -> Tuple[float, float]: - rho, T = parr - delta = rho/rhoc - tau = Tc/T - - ideal = self._phi0(tau, delta) - fird = self.residual.phird(tau, delta) - firt = self.residual.phirt(tau, delta) - Po = (1+delta*fird)*self.R*T*rho - ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) - - return ho-Po/rho-u, ho-h - - sol = fsolve(f2, [rhoo, To], full_output=True) - rho, T = tuple(map(float, sol[0])) - rhol = self._Liquid_Density(T) - rhov = self._Vapor_Density(T) - if sol[2] != 1 or rhov <= rho <= rhol: - - def f4(parr: Tuple[float, float, float, float]) -> Tuple[ - float, float, float, float]: - T, rhol, rhog, x = parr - tau = Tc/T - deltaL = rhol/self._constant_rhoc - deltaG = rhog/self._constant_rhoc - - ideal = self._phi0(tau, deltaL) - - firL = self.residual.phir(tau, deltaL) - firdL = self.residual.phird(tau, deltaL) - firtL = self.residual.phirt(tau, deltaL) - hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) - firG = self.residual.phir(tau, deltaG) - firdG = self.residual.phird(tau, deltaG) - firtG = self.residual.phirt(tau, deltaG) - hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) - - Jl = rhol*(1+deltaL*firdL) - Jv = rhog*(1+deltaG*firdG) - K = firL-firG - - Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) - vu = hoG-Ps/rhog - lu = hoL-Ps/rhol - - return (Jl-Jv, - Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, - hoL*(1-x)+hoG*x - h, - lu*(1-x)+vu*x - u) - - for to in [To, 300, 400, 500, 600]: - rLo = self._Liquid_Density(to) - rGo = self._Vapor_Density(to) - sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) - T, rhoL, rhoG, x = tuple(map(float, sol[0])) - if sol[2] == 1 and 0 <= x <= 1 and \ - sum(abs(sol[1]["fvec"])) < 1e-5: - break - - if sum(abs(sol[1]["fvec"])) > 1e-5: - raise(RuntimeError(sol[3])) - - liquido = self._Helmholtz(rhoL, T) - vapor = self._Helmholtz(rhoG, T) - P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( - liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 - - elif self._mode == "su": - def f2(parr: Tuple[float, float]) -> Tuple[float, float]: - rho, T = parr - delta = rho/rhoc - tau = Tc/T - - ideal = self._phi0(tau, delta) - fird = self.residual.phird(tau, delta) - fir = self.residual.phir(tau, delta) - firt = self.residual.phirt(tau, delta) - ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) - so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) - Po = (1+delta*fird)*self.R*T*rho - return ho-Po/rho-u, so-s - - sol = fsolve(f2, [rhoo, To], full_output=True) - rho, T = tuple(map(float, sol[0])) - rhol = self._Liquid_Density(T) - rhov = self._Vapor_Density(T) - if sol[2] != 1 or rhov <= rho <= rhol: - - def f4(parr: Tuple[float, float, float, float]) -> Tuple[ - float, float, float, float]: - T, rhol, rhog, x = parr - tau = Tc/T - deltaL = rhol/self._constant_rhoc - deltaG = rhog/self._constant_rhoc - - idealL = self._phi0(tau, deltaL) - idealG = self._phi0(tau, deltaG) - - firL = self.residual.phir(tau, deltaL) - firdL = self.residual.phird(tau, deltaL) - firtL = self.residual.phirt(tau, deltaL) - hoL = self.R*T*(1+tau*(idealL.fit+firtL)+deltaL*firdL) - soL = self.R*(tau*(idealL.fit+firtL)-idealL.fi-firL) - firG = self.residual.phir(tau, deltaG) - firdG = self.residual.phird(tau, deltaG) - firtG = self.residual.phirt(tau, deltaG) - hoG = self.R*T*(1+tau*(idealL.fit+firtG)+deltaG*firdG) - soG = self.R*(tau*(idealL.fit+firtG)-idealG.fi-firG) - - Jl = rhol*(1+deltaL*firdL) - Jv = rhog*(1+deltaG*firdG) - K = firL-firG - - try: - logrho = log(rhol/rhog) - except ValueError: - logrho = float('nan') - Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+logrho) - vu = hoG-Ps/rhog - lu = hoL-Ps/rhol - - return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, - soL*(1-x)+soG*x - s, lu*(1-x)+vu*x - u) - - for to in [To, 300, 400, 500, 600]: - rLo = self._Liquid_Density(to) - rGo = self._Vapor_Density(to) - sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) - T, rhoL, rhoG, x = tuple(map(float, sol[0])) - if sol[2] == 1 and 0 <= x <= 1 and \ - sum(abs(sol[1]["fvec"])) < 1e-5: - break - - if sum(abs(sol[1]["fvec"])) > 1e-5: - raise(RuntimeError(sol[3])) - - liquido = self._Helmholtz(rhoL, T) - vapor = self._Helmholtz(rhoG, T) - P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( - liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 - - elif self._mode == "Trho": - if T < self._constant_Tref: - rhov = self._Vapor_Density(T) - rhol = self._Liquid_Density(T) - if rhol > rho > rhov: - rhol, rhov, Ps = self._saturation(T) - if rhol > rho > rhov: - vapor = self._Helmholtz(rhov, T) - liquido = self._Helmholtz(rhol, T) - x = (1/rho-1/rhol)/(1/rhov-1/rhol) - P = Ps/1000 - - rho = float(rho) - T = float(T) - propiedades = self._Helmholtz(rho, T) - - if T > self._constant_Tref: - x = 1 - elif x is None: - x = 0 - - if not P: - P = propiedades.P/1000. + Jl = rhol*(1+deltaL*firdL) + Jv = rhog*(1+deltaG*firdG) + K = firL-firG + try: + logrho = log(rhol/rhog) + except ValueError: + logrho = float('nan') + Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+logrho) + return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, Ps - P*1000) + + for to in [To, 300, 400, 500, 600]: + rhoLo = self._Liquid_Density(to) + rhoGo = self._Vapor_Density(to) + sol = fsolve(f3, [to, rhoLo, rhoGo], full_output=True) + T, rhoL, rhoG = tuple(map(float, sol[0])) + x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) + if sol[2] == 1 and 0 <= x <= 1 and \ + sum(abs(sol[1]["fvec"])) < 1e-5: + break + + if sum(abs(sol[1]["fvec"])) > 1e-5: + raise(RuntimeError(sol[3])) + + liquido = self._Helmholtz(rhoL, T) + vapor = self._Helmholtz(rhoG, T) + P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( + liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 + + self.solve_case1(T, P, x, rho, liquido, vapor) + + def solve_P_h(self, P: float, h: float, rhoo: float, To: float) -> None: + """Solve for properties using P & h.""" + x = None - elif self._mode == "Tx": - # Check input T in saturation range - if self.Tt > T or self._constant_Tref < T or x > 1 or x < 0: - raise NotImplementedError("Incoming out of bound") + def f2(parr: Tuple[float, float]) -> Tuple[float, float]: + rho, T = parr + delta = rho/rhoc + tau = self._constant_Tref/T + + ideal = self._phi0(tau, delta) + fird = self.residual.phird(tau, delta) + firt = self.residual.phirt(tau, delta) + Po = (1+delta*fird)*self.R*T*rho + ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) + return Po-P*1000, ho-h + + rho, T = tuple(map(float, fsolve(f2, [rhoo, To]))) + rhol = self._Liquid_Density(T) + rhov = self._Vapor_Density(T) + liquido = None + vapor = None + if rho == rhoo or rhov <= rho <= rhol: + + def f4(parr: Tuple[float, float, float, float]) -> Tuple[ + float, float, float, float]: + T, rhol, rhog, x = parr + tau = self._constant_Tref/T + deltaL = rhol/self._constant_rhoc + deltaG = rhog/self._constant_rhoc + + ideal = self._phi0(tau, deltaL) + firL = self.residual.phir(tau, deltaL) + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) + hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) + firG = self.residual.phir(tau, deltaG) + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) + hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) + + Jl = rhol*(1+deltaL*firdL) + Jv = rhog*(1+deltaG*firdG) + K = firL-firG + Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) + + return (Jl-Jv, + Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, + hoL*(1-x)+hoG*x - h, + Ps - P*1000) + + for to in [To, 300, 400, 500, 600]: + rLo = self._Liquid_Density(to) + rGo = self._Vapor_Density(to) + sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) + T, rhoL, rhoG, x = tuple(map(float, sol[0])) + if sol[2] == 1 and 0 <= x <= 1 and \ + sum(abs(sol[1]["fvec"])) < 1e-5: + break + + if sum(abs(sol[1]["fvec"])) > 1e-5: + raise(RuntimeError(sol[3])) + + liquido = self._Helmholtz(rhoL, T) + vapor = self._Helmholtz(rhoG, T) + P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( + liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 + + self.solve_case1(T, P, x, rho, liquido, vapor) + + def solve_P_s(self, P: float, s: float, rhoo: float, + To: float, x0: Optional[float]) -> None: + """Solve for properties using P & s.""" + if x0 is None or x0 == 0 or x0 == 1: + + def f2(parr: Tuple[float, float]) -> Tuple[float, float]: + rho, T = parr + delta = rho/rhoc + tau = self._constant_Tref/T + + ideal = self._phi0(tau, delta) + fird = self.residual.phird(tau, delta) + fir = self.residual.phir(tau, delta) + firt = self.residual.phirt(tau, delta) + Po = (1+delta*fird)*self.R*T*rho + so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) + return Po-P*1000, so-s + + rho, T = tuple(map(float, fsolve(f2, [rhoo, To]))) + liquido = None + vapor = None + x = None + else: + + def f2(parr: Tuple[float, float]) -> Tuple[float, float]: + rho, T = parr + rhol, rhov, Ps = self._saturation(T) + vapor = self._Helmholtz(rhov, T) + liquido = self._Helmholtz(rhol, T) + x = (1./rho-1/rhol)/(1/rhov-1/rhol) + return Ps-P*1000, vapor.s*x+liquido.s*(1-x)-s + rho, T = tuple(map(float, fsolve(f2, [2., 500.]))) rhol, rhov, Ps = self._saturation(T) vapor = self._Helmholtz(rhov, T) liquido = self._Helmholtz(rhol, T) - if x == 0: - propiedades = liquido - elif x == 1: - propiedades = vapor - P = Ps/1000. + x = (s-liquido.s)/(vapor.s-liquido.s) - elif self._mode == "Px": - # Check input P in saturation range - if self.Pc < P or x > 1 or x < 0: - raise NotImplementedError("Incoming out of bound") + self.solve_case1(T, P, x, rho, liquido, vapor) - # Iterate over saturation routine to get T - def t_func(T: float) -> float: - rhol = self._Liquid_Density(T) - rhog = self._Vapor_Density(T) + def solve_P_u(self, P: float, u: float, rhoo: float, To: float) -> None: + """Solve for properties using P & u.""" + x = None + def f2(parr: Tuple[float, float]) -> Tuple[float, float]: + rho, T = parr + delta = rho/rhoc + tau = self._constant_Tref/T + + ideal = self._phi0(tau, delta) + fird = self.residual.phird(tau, delta) + firt = self.residual.phirt(tau, delta) + Po = (1+delta*fird)*self.R*T*rho + ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) + return ho-Po/rho-u, Po-P*1000 + + sol = fsolve(f2, [rhoo, To], full_output=True) + rho, T = tuple(map(float, sol[0])) + rhol = self._Liquid_Density(T) + rhov = self._Vapor_Density(T) + liquido = None + vapor = None + if rho == rhoo or sol[2] != 1: + + def f4(parr: Tuple[float, float, float, float]) -> Tuple[ + float, float, float, float]: + T, rhol, rhog, x = parr + tau = self._constant_Tref/T deltaL = rhol/self._constant_rhoc deltaG = rhog/self._constant_rhoc - tau = Tc/T + ideal = self._phi0(tau, deltaL) firL = self.residual.phir(tau, deltaL) + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) + hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) firG = self.residual.phir(tau, deltaG) - Ps = self.R*T*rhol*rhog/(rhol-rhog)*( - firL-firG+log(deltaL/deltaG)) - return Ps/1000-P - - if T0: - To = T0 - elif self.name == "water": - To = _TSat_P(P) - else: - To = (self._constant_Tref+self.Tt)/2 - T = float(fsolve(t_func, To)[0]) - rhol, rhov, Ps = self._saturation(T) - vapor = self._Helmholtz(rhov, T) - liquido = self._Helmholtz(rhol, T) - if x == 0: - propiedades = liquido - elif x == 1: - propiedades = vapor + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) + hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) + + Jl = rhol*(1+deltaL*firdL) + Jv = rhog*(1+deltaG*firdG) + K = firL-firG + try: + logrho = log(rhol/rhog) + except ValueError: + logrho = float('nan') + Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+logrho) + vu = hoG-Ps/rhog + lu = hoL-Ps/rhol + return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, + lu*(1-x)+vu*x - u, Ps - P*1000) + + for to in [To, 300, 400, 500, 600]: + rLo = self._Liquid_Density(to) + rGo = self._Vapor_Density(to) + sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) + T, rhoL, rhoG, x = tuple(map(float, sol[0])) + if sol[2] == 1 and 0 <= x <= 1 and \ + sum(abs(sol[1]["fvec"])) < 1e-5: + break + + if sum(abs(sol[1]["fvec"])) > 1e-5: + raise(RuntimeError(sol[3])) + + liquido = self._Helmholtz(rhoL, T) + vapor = self._Helmholtz(rhoG, T) + P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( + liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 + + self.solve_case1(T, P, x, rho, liquido, vapor) + + def solve_rho_h(self, rho: float, h: float, To: float) -> None: + """Solve for properties using rho & h.""" + delta = rho/rhoc + P = 0.0 + x = None + + def t_func(T: float) -> float: + tau = self._constant_Tref/T + + ideal = self._phi0(tau, delta) + fird = self.residual.phird(tau, delta) + firt = self.residual.phirt(tau, delta) + ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) + return ho-h + + T = float(fsolve(t_func, To)[0]) + rhol = self._Liquid_Density(T) + rhov = self._Vapor_Density(T) + liquido = None + vapor = None + if T == To or rhov <= rho <= rhol: + def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: + T, rhol, rhog = parr + tau = self._constant_Tref/T + deltaL = rhol/self._constant_rhoc + deltaG = rhog/self._constant_rhoc + + ideal = self._phi0(tau, deltaL) + firL = self.residual.phir(tau, deltaL) + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) + hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) + firG = self.residual.phir(tau, deltaG) + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) + hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) + + Jl = rhol*(1+deltaL*firdL) + Jv = rhog*(1+deltaG*firdG) + K = firL-firG + x = (1./rho-1/rhol)/(1/rhog-1/rhol) + try: + logrho = log(rhol/rhog) + except ValueError: + logrho = float('nan') + return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, + hoL*(1-x)+hoG*x - h) + + for to in [To, 300, 400, 500, 600]: + rhoLo = self._Liquid_Density(to) + rhoGo = self._Vapor_Density(to) + sol = fsolve(f3, [to, rhoLo, rhoGo], full_output=True) + T, rhoL, rhoG = tuple(map(float, sol[0])) + x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) + if sol[2] == 1 and 0 <= x <= 1 and \ + sum(abs(sol[1]["fvec"])) < 1e-5: + break + + if sum(abs(sol[1]["fvec"])) > 1e-5: + raise(RuntimeError(sol[3])) + + liquido = self._Helmholtz(rhoL, T) + vapor = self._Helmholtz(rhoG, T) + P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( + liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 + + self.solve_case1(T, P, x, rho, liquido, vapor) + + def solve_rho_s(self, rho: float, s: float, To: float) -> None: + """Solve for properties using rho & s.""" + delta = rho/rhoc + P = 0.0 + x = None + + def t_func(T: float) -> float: + tau = self._constant_Tref/T + ideal = self._phi0(tau, delta) + fir = self.residual.phir(tau, delta) + firt = self.residual.phirt(tau, delta) + so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) + return so-s + + T = float(fsolve(t_func, To)[0]) + rhol = self._Liquid_Density(T) + rhov = self._Vapor_Density(T) + liquido = None + vapor = None + if T == To or rhov <= rho <= rhol: + + def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: + T, rhol, rhog = parr + tau = self._constant_Tref/T + deltaL = rhol/self._constant_rhoc + deltaG = rhog/self._constant_rhoc + + idealL = self._phi0(tau, deltaL) + idealG = self._phi0(tau, deltaG) + + firL = self.residual.phir(tau, deltaL) + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) + soL = self.R*(tau*(idealL.fit+firtL)-idealL.fi-firL) + firG = self.residual.phir(tau, deltaG) + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) + soG = self.R*(tau*(idealL.fit+firtG)-idealG.fi-firG) + + Jl = rhol*(1+deltaL*firdL) + Jv = rhog*(1+deltaG*firdG) + K = firL-firG + x = (1./rho-1/rhol)/(1/rhog-1/rhol) + try: + logrho = log(rhol/rhog) + except ValueError: + logrho = float('nan') + return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, + soL*(1-x)+soG*x - s) + + for to in [To, 300, 400, 500, 600]: + rhoLo = self._Liquid_Density(to) + rhoGo = self._Vapor_Density(to) + sol = fsolve(f3, [to, rhoLo, rhoGo], full_output=True) + T, rhoL, rhoG = tuple(map(float, sol[0])) + x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) + if sol[2] == 1 and 0 <= x <= 1 and \ + sum(abs(sol[1]["fvec"])) < 1e-5: + break + + if sum(abs(sol[1]["fvec"])) > 1e-5: + raise(RuntimeError(sol[3])) + + liquido = self._Helmholtz(rhoL, T) + vapor = self._Helmholtz(rhoG, T) + P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( + liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 + + self.solve_case1(T, P, x, rho, liquido, vapor) + + def solve_rho_u(self, rho: float, u: float, rhoo: float, To: float) -> None: + """Solve for properties using rho & u.""" + delta = rho/rhoc + P = 0.0 + x = None + + def t_func(T: float) -> float: + tau = self._constant_Tref/T + + ideal = self._phi0(tau, delta) + fird = self.residual.phird(tau, delta) + firt = self.residual.phirt(tau, delta) + Po = (1+delta*fird)*self.R*T*rho + ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) + return ho-Po/rho-u + + T = float(fsolve(t_func, To)[0]) + rhol = self._Liquid_Density(T) + rhov = self._Vapor_Density(T) + liquido = None + vapor = None + if T == To or rhov <= rho <= rhol: + def f3(parr: Tuple[float, float, float]) -> Tuple[float, float, float]: + T, rhol, rhog = parr + tau = self._constant_Tref/T + deltaL = rhol/self._constant_rhoc + deltaG = rhog/self._constant_rhoc + + ideal = self._phi0(tau, deltaL) + firL = self.residual.phir(tau, deltaL) + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) + hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) + firG = self.residual.phir(tau, deltaG) + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) + hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) + + Jl = rhol*(1+deltaL*firdL) + Jv = rhog*(1+deltaG*firdG) + K = firL-firG + x = (1./rho-1/rhol)/(1/rhog-1/rhol) + try: + logrho = log(rhol/rhog) + except ValueError: + logrho = float('nan') + Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+logrho) + vu = hoG-Ps/rhog + lu = hoL-Ps/rhol + return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, + lu*(1-x)+vu*x - u) + + for to in [To, 300, 400, 500, 600]: + rhoLo = self._Liquid_Density(to) + rhoGo = self._Vapor_Density(to) + sol = fsolve(f3, [to, rhoLo, rhoGo], full_output=True) + T, rhoL, rhoG = tuple(map(float, sol[0])) + x = (1./rho-1/rhoL)/(1/rhoG-1/rhoL) + if sol[2] == 1 and 0 <= x <= 1 and \ + sum(abs(sol[1]["fvec"])) < 1e-5: + break + + if sum(abs(sol[1]["fvec"])) > 1e-5: + raise(RuntimeError(sol[3])) + + liquido = self._Helmholtz(rhoL, T) + vapor = self._Helmholtz(rhoG, T) + P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( + liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 + + self.solve_case1(T, P, x, rho, liquido, vapor) + + def solve_h_s(self, h: float, s: float, rhoo: float, To: float) -> None: + """Solve for properties using h & s.""" + P = 0.0 + x = None + + def f2(parr: Tuple[float, float]) -> Tuple[float, float]: + rho, T = parr + delta = rho/rhoc + tau = self._constant_Tref/T + + ideal = self._phi0(tau, delta) + fird = self.residual.phird(tau, delta) + fir = self.residual.phir(tau, delta) + firt = self.residual.phirt(tau, delta) + ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) + so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) + return ho-h, so-s + + rho, T = tuple(map(float, fsolve(f2, [rhoo, To]))) + rhol = self._Liquid_Density(T) + rhov = self._Vapor_Density(T) + liquido = None + vapor = None + if rhov <= rho <= rhol: + + def f4(parr: Tuple[float, float, float, float]) -> Tuple[ + float, float, float, float]: + T, rhol, rhog, x = parr + tau = self._constant_Tref/T + deltaL = rhol/self._constant_rhoc + deltaG = rhog/self._constant_rhoc + + idealL = self._phi0(tau, deltaL) + idealG = self._phi0(tau, deltaG) + + firL = self.residual.phir(tau, deltaL) + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) + hoL = self.R*T*(1+tau*(idealL.fit+firtL)+deltaL*firdL) + soL = self.R*(tau*(idealL.fit+firtL)-idealL.fi-firL) + firG = self.residual.phir(tau, deltaG) + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) + hoG = self.R*T*(1+tau*(idealL.fit+firtG)+deltaG*firdG) + soG = self.R*(tau*(idealL.fit+firtG)-idealG.fi-firG) + + Jl = rhol*(1+deltaL*firdL) + Jv = rhog*(1+deltaG*firdG) + K = firL-firG + return (Jl-Jv, + Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, + hoL*(1-x)+hoG*x - h, + soL*(1-x)+soG*x - s) + + for to in [To, 300, 400, 500, 600]: + rLo = self._Liquid_Density(to) + rGo = self._Vapor_Density(to) + sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) + T, rhoL, rhoG, x = tuple(map(float, sol[0])) + if sol[2] == 1 and 0 <= x <= 1 and \ + sum(abs(sol[1]["fvec"])) < 1e-5: + break + + if sum(abs(sol[1]["fvec"])) > 1e-5: + raise(RuntimeError(sol[3])) + + liquido = self._Helmholtz(rhoL, T) + vapor = self._Helmholtz(rhoG, T) + P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( + liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 + + self.solve_case1(T, P, x, rho, liquido, vapor) + + def solve_h_u(self, h: float, u: float, rhoo: float, To: float) -> None: + """Solve for properties using h & u.""" + P = 0.0 + x = None + + def f2(parr: Tuple[float, float]) -> Tuple[float, float]: + rho, T = parr + delta = rho/rhoc + tau = self._constant_Tref/T + + ideal = self._phi0(tau, delta) + fird = self.residual.phird(tau, delta) + firt = self.residual.phirt(tau, delta) + Po = (1+delta*fird)*self.R*T*rho + ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) + + return ho-Po/rho-u, ho-h + + sol = fsolve(f2, [rhoo, To], full_output=True) + rho, T = tuple(map(float, sol[0])) + rhol = self._Liquid_Density(T) + rhov = self._Vapor_Density(T) + liquido = None + vapor = None + if sol[2] != 1 or rhov <= rho <= rhol: + + def f4(parr: Tuple[float, float, float, float]) -> Tuple[ + float, float, float, float]: + T, rhol, rhog, x = parr + tau = self._constant_Tref/T + deltaL = rhol/self._constant_rhoc + deltaG = rhog/self._constant_rhoc + + ideal = self._phi0(tau, deltaL) + + firL = self.residual.phir(tau, deltaL) + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) + hoL = self.R*T*(1+tau*(ideal.fit+firtL)+deltaL*firdL) + firG = self.residual.phir(tau, deltaG) + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) + hoG = self.R*T*(1+tau*(ideal.fit+firtG)+deltaG*firdG) + + Jl = rhol*(1+deltaL*firdL) + Jv = rhog*(1+deltaG*firdG) + K = firL-firG + + Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+log(rhol/rhog)) + vu = hoG-Ps/rhog + lu = hoL-Ps/rhol + + return (Jl-Jv, + Jl*(1/rhog-1/rhol)-log(rhol/rhog)-K, + hoL*(1-x)+hoG*x - h, + lu*(1-x)+vu*x - u) + + for to in [To, 300, 400, 500, 600]: + rLo = self._Liquid_Density(to) + rGo = self._Vapor_Density(to) + sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) + T, rhoL, rhoG, x = tuple(map(float, sol[0])) + if sol[2] == 1 and 0 <= x <= 1 and \ + sum(abs(sol[1]["fvec"])) < 1e-5: + break + + if sum(abs(sol[1]["fvec"])) > 1e-5: + raise(RuntimeError(sol[3])) + + liquido = self._Helmholtz(rhoL, T) + vapor = self._Helmholtz(rhoG, T) + P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( + liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 + + self.solve_case1(T, P, x, rho, liquido, vapor) + + def solve_s_u(self, s: float, u: float, rhoo: float, To: float) -> None: + """Solve for properties using s & u.""" + P = 0.0 + x = None + + def f2(parr: Tuple[float, float]) -> Tuple[float, float]: + rho, T = parr + delta = rho/rhoc + tau = self._constant_Tref/T + + ideal = self._phi0(tau, delta) + fird = self.residual.phird(tau, delta) + fir = self.residual.phir(tau, delta) + firt = self.residual.phirt(tau, delta) + ho = self.R*T*(1+tau*(ideal.fit+firt)+delta*fird) + so = self.R*(tau*(ideal.fit+firt)-ideal.fi-fir) + Po = (1+delta*fird)*self.R*T*rho + return ho-Po/rho-u, so-s + + sol = fsolve(f2, [rhoo, To], full_output=True) + rho, T = tuple(map(float, sol[0])) + rhol = self._Liquid_Density(T) + rhov = self._Vapor_Density(T) + liquido = None + vapor = None + if sol[2] != 1 or rhov <= rho <= rhol: + + def f4(parr: Tuple[float, float, float, float]) -> Tuple[ + float, float, float, float]: + T, rhol, rhog, x = parr + tau = self._constant_Tref/T + deltaL = rhol/self._constant_rhoc + deltaG = rhog/self._constant_rhoc + + idealL = self._phi0(tau, deltaL) + idealG = self._phi0(tau, deltaG) + + firL = self.residual.phir(tau, deltaL) + firdL = self.residual.phird(tau, deltaL) + firtL = self.residual.phirt(tau, deltaL) + hoL = self.R*T*(1+tau*(idealL.fit+firtL)+deltaL*firdL) + soL = self.R*(tau*(idealL.fit+firtL)-idealL.fi-firL) + firG = self.residual.phir(tau, deltaG) + firdG = self.residual.phird(tau, deltaG) + firtG = self.residual.phirt(tau, deltaG) + hoG = self.R*T*(1+tau*(idealL.fit+firtG)+deltaG*firdG) + soG = self.R*(tau*(idealL.fit+firtG)-idealG.fi-firG) + + Jl = rhol*(1+deltaL*firdL) + Jv = rhog*(1+deltaG*firdG) + K = firL-firG + + try: + logrho = log(rhol/rhog) + except ValueError: + logrho = float('nan') + Ps = self.R*T*rhol*rhog/(rhol-rhog)*(K+logrho) + vu = hoG-Ps/rhog + lu = hoL-Ps/rhol + + return (Jl-Jv, Jl*(1/rhog-1/rhol)-logrho-K, + soL*(1-x)+soG*x - s, lu*(1-x)+vu*x - u) + + for to in [To, 300, 400, 500, 600]: + rLo = self._Liquid_Density(to) + rGo = self._Vapor_Density(to) + sol = fsolve(f4, [to, rLo, rGo, 0.5], full_output=True) + T, rhoL, rhoG, x = tuple(map(float, sol[0])) + if sol[2] == 1 and 0 <= x <= 1 and sum(abs(sol[1]["fvec"])) < 1e-5: + break + + if sum(abs(sol[1]["fvec"])) > 1e-5: + raise(RuntimeError(sol[3])) + + liquido = self._Helmholtz(rhoL, T) + vapor = self._Helmholtz(rhoG, T) + P = self.R*T*rhoL*rhoG/(rhoL-rhoG)*( + liquido.fir-vapor.fir+log(rhoL/rhoG))/1000 + + self.solve_case1(T, P, x, rho, liquido, vapor) + + def solve_T_rho(self, T: float, rho: float) -> None: + """Solve for properties using T & rho.""" + P = 0.0 + x = None + liquido = None + vapor = None + if T < self._constant_Tref: + rhov = self._Vapor_Density(T) + rhol = self._Liquid_Density(T) + if rhol > rho > rhov: + rhol, rhov, Ps = self._saturation(T) + if rhol > rho > rhov: + vapor = self._Helmholtz(rhov, T) + liquido = self._Helmholtz(rhol, T) + x = (1/rho-1/rhol)/(1/rhov-1/rhol) + P = Ps/1000 + self.solve_case1(T, P, x, rho, liquido, vapor) + + def solve_case1(self, T: float, P: float, x: Optional[float], rho: float, + liquido: Optional[MEoSProperties], + vapor: Optional[MEoSProperties]) -> None: + """Post processing for most solve cases except Tx and Px.""" + # T, P, rho and x are really sometimes float and sometimes int. + T = float(T) + P = float(P) + rho = float(rho) + if x is not None: + x = float(x) + propiedades = self._Helmholtz(rho, T) + + if T > self._constant_Tref: + x = 1.0 + elif x is None: + x = 0.0 + + if not P: + P = propiedades.P/1000. + self.dofill(T, P, x, propiedades, liquido, vapor) + + def solve_T_x(self, T: float, x: float) -> None: + """Solve for properties using T & x.""" + # Check input T in saturation range + if self.Tt > T or self._constant_Tref < T or x > 1 or x < 0: + raise NotImplementedError("Incoming out of bound") + + rhol, rhov, Ps = self._saturation(T) + vapor = self._Helmholtz(rhov, T) + liquido = self._Helmholtz(rhol, T) + propiedades: Optional[MEoSProperties] = None + if x == 0.0: + propiedades = liquido + elif x == 1.0: + propiedades = vapor + P = Ps/1000.0 + self.dofill(T, P, x, propiedades, liquido, vapor) + + def solve_P_x(self, P: float, x: float, T0: Optional[float]) -> None: + """Solve for properties using P & x.""" + # Check input P in saturation range + if self.Pc < P or x > 1 or x < 0: + raise NotImplementedError("Incoming out of bound") + + # Iterate over saturation routine to get T + def t_func(T: float) -> float: + rhol = self._Liquid_Density(T) + rhog = self._Vapor_Density(T) + + deltaL = rhol/self._constant_rhoc + deltaG = rhog/self._constant_rhoc + + tau = self._constant_Tref/T + firL = self.residual.phir(tau, deltaL) + firG = self.residual.phir(tau, deltaG) + Ps = self.R*T*rhol*rhog/(rhol-rhog)*( + firL-firG+log(deltaL/deltaG)) + return Ps/1000-P + + if T0: + To = T0 + elif self.name == "water": + To = _TSat_P(P) + else: + To = (self._constant_Tref+self.Tt)/2 + T = float(fsolve(t_func, To)[0]) + rhol, rhov, Ps = self._saturation(T) + vapor = self._Helmholtz(rhov, T) + liquido = self._Helmholtz(rhol, T) + propiedades: Optional[MEoSProperties] = None + if x == 0.0: + propiedades = liquido + elif x == 1.0: + propiedades = vapor + self.dofill(T, P, x, propiedades, liquido, vapor) + + def dofill(self, T, P, x, propiedades, liquido, vapor): + """Finish filling the class.""" self.T = T self.Tr = T/self._constant_Tref self.P = P @@ -1242,11 +1394,11 @@ def t_func(T: float) -> float: self.Liquid = _fase() self.Gas = _fase() - if x == 0: + if x == 0.0: # liquid phase self.fill(self.Liquid, propiedades) self.fill(self, propiedades) - elif x == 1: + elif x == 1.0: # vapor phase self.fill(self.Gas, propiedades) self.fill(self, propiedades) @@ -1402,11 +1554,10 @@ def derivative(self, z: str, x: str, y: str, fase: _fase) -> float: def _saturation(self, T: float) -> Tuple[float, float, float]: """Saturation calculation for two phase search""" rhoc = self._constant_rhoc - Tc = self._constant_Tref - if T > Tc: - T = Tc - tau = Tc/T + if T > self._constant_Tref: + T = self._constant_Tref + tau = self._constant_Tref/T rhoLo = self._Liquid_Density(T) rhoGo = self._Vapor_Density(T) @@ -1473,10 +1624,8 @@ def _Helmholtz(self, rho: float, T: float) -> MEoSProperties: rho = 1e-20 if T < 50: T = 50 - rhoc = self._constant_rhoc - Tc = self._constant_Tref - delta = rho/rhoc - tau = Tc/T + delta = rho/self._constant_rhoc + tau = self._constant_Tref/T ideal = self._phi0(tau, delta) res = self.residual.helmholtz(tau, delta) @@ -1492,11 +1641,8 @@ def _Helmholtz(self, rho: float, T: float) -> MEoSProperties: def _prop0(self, rho: float, T: float) -> _fase: """Ideal gas properties""" - rhoc = self._constant_rhoc - Tc = self._constant_Tref - - delta = rho/rhoc - tau = Tc/T + delta = rho/self._constant_rhoc + tau = self._constant_Tref/T ideal = self._phi0(tau, delta) propiedades = _fase() From fbfd2fe7ebdbf27b6f3fe492b783795d0c40a257 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 20 Mar 2021 13:19:03 -0400 Subject: [PATCH 098/102] Remove to two unused variables. While there was a lot of farily arbitrary restructuring in the previous commit, this change was the one that seemed to be the most substantively different. These two variables really do seem to have just been unused, whereas most of the other changes were more obviously stylistic or caused by changes in data flow. --- iapws/iapws95.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 99f27d9..d8266a5 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -788,8 +788,6 @@ def f2(parr: Tuple[float, float]) -> Tuple[float, float]: sol = fsolve(f2, [rhoo, To], full_output=True) rho, T = tuple(map(float, sol[0])) - rhol = self._Liquid_Density(T) - rhov = self._Vapor_Density(T) liquido = None vapor = None if rho == rhoo or sol[2] != 1: From db8243de6541943cbe0396ab27c2a1277b47c8aa Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 20 Mar 2021 13:40:20 -0400 Subject: [PATCH 099/102] Call calculo to determine if state is calculable. This is beneficial for mypy (and also for humans to some extent) because it struggles with code paradigms like _mode where variables are tested for types in one place, then summarized in _mode, and then used logically in distant code that presumes the logic is sound. By placing the actual tests closer to the usage, mypy is able to figure out, and humans can more easily verify that the constraints are enforced. --- iapws/iapws95.py | 130 +++++++++++++++++++++-------------------------- 1 file changed, 57 insertions(+), 73 deletions(-) diff --git a/iapws/iapws95.py b/iapws/iapws95.py index d8266a5..229b1b8 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -250,65 +250,29 @@ def __call__(self, **kwargs) -> None: del kwargs["vm"] self.kwargs.update(kwargs) - if self.calculable: - try: - self.status = 1 - self.calculo() - self.msg = "" - except RuntimeError as err: - self.status = 0 - self.msg = err.args[0] - raise(err) - - # Add msg for extrapolation state - if self.name == "water" and 130 <= self.T < 273.15: - self.msg = "Extrapolated state" - self.status = 3 - warnings.warn("Using extrapolated values") - elif self.name == "water" and 50 <= self.T < 130: - self.msg = "Extrapolated state using Low-Temperature extension" - self.status = 3 - warnings.warn("Using extrapolated values and Low-Temperature" - "extension") + try: + self.calculo() + self.msg = "" + if self.status == 0: + return + except RuntimeError as err: + self.status = 0 + self.msg = err.args[0] + raise(err) + + # Add msg for extrapolation state + if self.name == "water" and 130 <= self.T < 273.15: + self.msg = "Extrapolated state" + self.status = 3 + warnings.warn("Using extrapolated values") + elif self.name == "water" and 50 <= self.T < 130: + self.msg = "Extrapolated state using Low-Temperature extension" + self.status = 3 + warnings.warn("Using extrapolated values and Low-Temperature extension") @property def calculable(self) -> bool: """Check if inputs are enough to define state""" - self._mode = "" - if self.kwargs["T"] and self.kwargs["P"]: - self._mode = "TP" - elif self.kwargs["T"] and self.kwargs["rho"]: - self._mode = "Trho" - elif self.kwargs["T"] and self.kwargs["h"] is not None: - self._mode = "Th" - elif self.kwargs["T"] and self.kwargs["s"] is not None: - self._mode = "Ts" - elif self.kwargs["T"] and self.kwargs["u"] is not None: - self._mode = "Tu" - elif self.kwargs["P"] and self.kwargs["rho"]: - self._mode = "Prho" - elif self.kwargs["P"] and self.kwargs["h"] is not None: - self._mode = "Ph" - elif self.kwargs["P"] and self.kwargs["s"] is not None: - self._mode = "Ps" - elif self.kwargs["P"] and self.kwargs["u"] is not None: - self._mode = "Pu" - elif self.kwargs["rho"] and self.kwargs["h"] is not None: - self._mode = "rhoh" - elif self.kwargs["rho"] and self.kwargs["s"] is not None: - self._mode = "rhos" - elif self.kwargs["rho"] and self.kwargs["u"] is not None: - self._mode = "rhou" - elif self.kwargs["h"] is not None and self.kwargs["s"] is not None: - self._mode = "hs" - elif self.kwargs["h"] is not None and self.kwargs["u"] is not None: - self._mode = "hu" - elif self.kwargs["s"] is not None and self.kwargs["u"] is not None: - self._mode = "su" - elif self.kwargs["T"] and self.kwargs["x"] is not None: - self._mode = "Tx" - elif self.kwargs["P"] and self.kwargs["x"] is not None: - self._mode = "Px" return bool(self._mode) def get_To_rhoo_x0(self, T0: Optional[float], @@ -357,41 +321,60 @@ def calculo(self) -> None: rho0 = self.kwargs["rho0"] To, rhoo, x0 = self.get_To_rhoo_x0(T0, rho0) + self._mode = "" # Method with iteration necessary to get x - if self._mode == "TP": + if self.kwargs["T"] and self.kwargs["P"]: + self._mode = "Trho" self.solve_T_P(T, P, rho0, rhoo) - elif self._mode == "Th": + elif self.kwargs["T"] and self.kwargs["rho"]: + self._mode = "Trho" + self.solve_T_rho(T, rho) + elif self.kwargs["T"] and self.kwargs["h"] is not None: + self._mode = "Th" self.solve_T_h(T, h) - elif self._mode == "Ts": + elif self.kwargs["T"] and self.kwargs["s"] is not None: + self._mode = "Ts" self.solve_T_s(T, s) - elif self._mode == "Tu": + elif self.kwargs["T"] and self.kwargs["u"] is not None: + self._mode = "Tu" self.solve_T_u(T, u) - elif self._mode == "Prho": + elif self.kwargs["P"] and self.kwargs["rho"]: + self._mode = "Prho" self.solve_P_rho(P, rho, To) - elif self._mode == "Ph": + elif self.kwargs["P"] and self.kwargs["h"] is not None: + self._mode = "Ph" self.solve_P_h(P, h, rhoo, To) - elif self._mode == "Ps": + elif self.kwargs["P"] and self.kwargs["s"] is not None: + self._mode = "Ps" self.solve_P_s(P, s, rhoo, To, x0) - elif self._mode == "Pu": + elif self.kwargs["P"] and self.kwargs["u"] is not None: + self._mode = "Pu" self.solve_P_u(P, u, rhoo, To) - elif self._mode == "rhoh": + elif self.kwargs["rho"] and self.kwargs["h"] is not None: + self._mode = "rhoh" self.solve_rho_h(rho, h, To) - elif self._mode == "rhos": + elif self.kwargs["rho"] and self.kwargs["s"] is not None: + self._mode = "rhos" self.solve_rho_s(rho, s, To) - elif self._mode == "rhou": + elif self.kwargs["rho"] and self.kwargs["u"] is not None: + self._mode = "rhou" self.solve_rho_u(rho, u, rhoo, To) - elif self._mode == "hs": + elif self.kwargs["h"] is not None and self.kwargs["s"] is not None: + self._mode = "hs" self.solve_h_s(h, s, rhoo, To) - elif self._mode == "hu": + elif self.kwargs["h"] is not None and self.kwargs["u"] is not None: + self._mode = "hu" self.solve_h_u(h, u, rhoo, To) - elif self._mode == "su": + elif self.kwargs["s"] is not None and self.kwargs["u"] is not None: + self._mode = "su" self.solve_s_u(s, u, rhoo, To) - elif self._mode == "Trho": - self.solve_T_rho(T, rho) - elif self._mode == "Tx": + elif self.kwargs["T"] and self.kwargs["x"] is not None: + self._mode = "Tx" self.solve_T_x(T, x) - elif self._mode == "Px": + elif self.kwargs["P"] and self.kwargs["x"] is not None: + self._mode = "Px" self.solve_P_x(P, x, T0) + # if self._mode is unset, calculable() will return false. def solve_T_P(self, T: float, P: float, rho0: Optional[float], rhoo: float) -> None: @@ -1379,6 +1362,7 @@ def t_func(T: float) -> float: def dofill(self, T, P, x, propiedades, liquido, vapor): """Finish filling the class.""" + self.status = 1 self.T = T self.Tr = T/self._constant_Tref self.P = P From 6d7a6c01277774d687b96a17867137a39a211159 Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 20 Mar 2021 13:51:27 -0400 Subject: [PATCH 100/102] Convert kwargs to consistently use None for undefined parameters. Remove last remaining type ignores in iapws95.py, by more consistently checking for "is not None", which mypy understands. --- iapws/iapws95.py | 58 ++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/iapws/iapws95.py b/iapws/iapws95.py index 229b1b8..3b6fc56 100644 --- a/iapws/iapws95.py +++ b/iapws/iapws95.py @@ -181,10 +181,10 @@ class MEoS(_fase): _constant_rhoc: float _constant_Tref: float - kwargs = {"T": 0.0, - "P": 0.0, - "rho": 0.0, - "v": 0.0, + kwargs = {"T": None, + "P": None, + "rho": None, + "v": None, "h": None, "s": None, "u": None, @@ -309,69 +309,69 @@ def get_To_rhoo_x0(self, T0: Optional[float], def calculo(self) -> None: """Calculate procedure""" - T: float = self.kwargs["T"] # type: ignore - rho: float = self.kwargs["rho"] # type: ignore - P: float = self.kwargs["P"] # type: ignore - s: float = self.kwargs["s"] # type: ignore - h: float = self.kwargs["h"] # type: ignore - u: float = self.kwargs["u"] # type: ignore - x: float = self.kwargs["x"] # type: ignore - + T = self.kwargs["T"] + rho = self.kwargs["rho"] + P = self.kwargs["P"] + s = self.kwargs["s"] + h = self.kwargs["h"] + u = self.kwargs["u"] + x = self.kwargs["x"] T0 = self.kwargs["T0"] rho0 = self.kwargs["rho0"] + To, rhoo, x0 = self.get_To_rhoo_x0(T0, rho0) self._mode = "" # Method with iteration necessary to get x - if self.kwargs["T"] and self.kwargs["P"]: + if T is not None and P is not None: self._mode = "Trho" self.solve_T_P(T, P, rho0, rhoo) - elif self.kwargs["T"] and self.kwargs["rho"]: + elif T is not None and rho is not None: self._mode = "Trho" self.solve_T_rho(T, rho) - elif self.kwargs["T"] and self.kwargs["h"] is not None: + elif T is not None and h is not None: self._mode = "Th" self.solve_T_h(T, h) - elif self.kwargs["T"] and self.kwargs["s"] is not None: + elif T is not None and s is not None: self._mode = "Ts" self.solve_T_s(T, s) - elif self.kwargs["T"] and self.kwargs["u"] is not None: + elif T is not None and u is not None: self._mode = "Tu" self.solve_T_u(T, u) - elif self.kwargs["P"] and self.kwargs["rho"]: + elif P is not None and rho is not None: self._mode = "Prho" self.solve_P_rho(P, rho, To) - elif self.kwargs["P"] and self.kwargs["h"] is not None: + elif P is not None and h is not None: self._mode = "Ph" self.solve_P_h(P, h, rhoo, To) - elif self.kwargs["P"] and self.kwargs["s"] is not None: + elif P is not None and s is not None: self._mode = "Ps" self.solve_P_s(P, s, rhoo, To, x0) - elif self.kwargs["P"] and self.kwargs["u"] is not None: + elif P is not None and u is not None: self._mode = "Pu" self.solve_P_u(P, u, rhoo, To) - elif self.kwargs["rho"] and self.kwargs["h"] is not None: + elif rho is not None and h is not None: self._mode = "rhoh" self.solve_rho_h(rho, h, To) - elif self.kwargs["rho"] and self.kwargs["s"] is not None: + elif rho is not None and s is not None: self._mode = "rhos" self.solve_rho_s(rho, s, To) - elif self.kwargs["rho"] and self.kwargs["u"] is not None: + elif rho is not None and u is not None: self._mode = "rhou" self.solve_rho_u(rho, u, rhoo, To) - elif self.kwargs["h"] is not None and self.kwargs["s"] is not None: + elif h is not None and s is not None: self._mode = "hs" self.solve_h_s(h, s, rhoo, To) - elif self.kwargs["h"] is not None and self.kwargs["u"] is not None: + elif h is not None and u is not None: self._mode = "hu" self.solve_h_u(h, u, rhoo, To) - elif self.kwargs["s"] is not None and self.kwargs["u"] is not None: + elif s is not None and u is not None: self._mode = "su" self.solve_s_u(s, u, rhoo, To) - elif self.kwargs["T"] and self.kwargs["x"] is not None: + elif T is not None and x is not None: self._mode = "Tx" self.solve_T_x(T, x) - elif self.kwargs["P"] and self.kwargs["x"] is not None: + elif P is not None and x is not None: self._mode = "Px" self.solve_P_x(P, x, T0) # if self._mode is unset, calculable() will return false. From 1fcbca129bfd919af6010969af459bd29400544e Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 20 Mar 2021 14:03:09 -0400 Subject: [PATCH 101/102] Rename _thermo to _mode for consistency with iapws95. Also avoids confusion with the method of the same name on several other classes. --- iapws/iapws97.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/iapws/iapws97.py b/iapws/iapws97.py index d96f020..98fd5f6 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -4355,32 +4355,32 @@ def __call__(self, **kwargs) -> None: @property def calculable(self) -> str: """Check if class is calculable by its kwargs""" - self._thermo = "" + self._mode = "" if self.kwargs["T"] and self.kwargs["P"]: - self._thermo = "TP" + self._mode = "TP" elif self.kwargs["P"] and self.kwargs["h"] is not None: - self._thermo = "Ph" + self._mode = "Ph" elif self.kwargs["P"] and self.kwargs["s"] is not None: - self._thermo = "Ps" + self._mode = "Ps" # TODO: Add other pairs definitions options # elif self.kwargs["P"] and self.kwargs["v"]: - # self._thermo = "Pv" + # self._mode = "Pv" # elif self.kwargs["T"] and self.kwargs["s"] is not None: - # self._thermo = "Ts" + # self._mode = "Ts" elif self.kwargs["h"] is not None and self.kwargs["s"] is not None: - self._thermo = "hs" + self._mode = "hs" elif self.kwargs["T"] and self.kwargs["x"] is not None: - self._thermo = "Tx" + self._mode = "Tx" elif self.kwargs["P"] and self.kwargs["x"] is not None: - self._thermo = "Px" - return self._thermo + self._mode = "Px" + return self._mode def calculo(self) -> None: """Calculate procedure""" - arg1: float = self.kwargs[self._thermo[0]] # type: ignore - arg2: float = self.kwargs[self._thermo[1]] # type: ignore + arg1: float = self.kwargs[self._mode[0]] # type: ignore + arg2: float = self.kwargs[self._mode[1]] # type: ignore args = (arg1, arg2) - if self._thermo == "TP": + if self._mode == "TP": T, P = args region = _Bound_TP(T, P) if region == 1: @@ -4403,7 +4403,7 @@ def rho_funcion(rho: float) -> float: else: raise NotImplementedError("Incoming out of bound") - elif self._thermo == "Ph": + elif self._mode == "Ph": P, h = args region = _Bound_Ph(P, h) if region == 1: @@ -4445,7 +4445,7 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: else: raise NotImplementedError("Incoming out of bound") - elif self._thermo == "Ps": + elif self._mode == "Ps": P, s = args region = _Bound_Ps(P, s) if region == 1: @@ -4487,7 +4487,7 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: else: raise NotImplementedError("Incoming out of bound") - elif self._thermo == "hs": + elif self._mode == "hs": h, s = args region = _Bound_hs(h, s) if region == 1: @@ -4575,7 +4575,7 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: else: raise NotImplementedError("Incoming out of bound") - elif self._thermo == "Px": + elif self._mode == "Px": P, x = args T = _TSat_P(P) if Pt <= P < Pc and 0 < x < 1: @@ -4597,7 +4597,7 @@ def rho_funcion(rho: float) -> float: self.sigma = _Tension(T) propiedades.x = x - elif self._thermo == "Tx": + elif self._mode == "Tx": T, x = args P = _PSat_T(T) if 273.15 <= T < Tc and 0 < x < 1: From b7d2e09ef2dfa68b48139e1d0c12d5e80a66f82a Mon Sep 17 00:00:00 2001 From: "Cory F. Cohen" Date: Sat, 20 Mar 2021 14:55:19 -0400 Subject: [PATCH 102/102] Update IAPWS97 to better match IAPWS95 code structure. In comparison to the IAPWS95 changes, these changes were hardly needed because the code was already so much clearer. There were a couple of places where mypy had to be "accommodated" to remove the "type: noginore" comments. The first was moving the "is not None" tests closer the calls that used the variables, and the second was splitting out the _solve_X_X() functions because mypy doesn't cope well with sub-function declarations and conditional logic. Both changes were beneficial anyway in my opinion, drawing attention to an unusual computation of sigma in two cases, and generally providing strong assurances that the entire _solve_X_X() call chain doesn't otherwise update the object. I wish we had that feature in IAPWS95. --- iapws/iapws97.py | 550 ++++++++++++++++++++++++----------------------- 1 file changed, 286 insertions(+), 264 deletions(-) diff --git a/iapws/iapws97.py b/iapws/iapws97.py index 98fd5f6..b087da0 100644 --- a/iapws/iapws97.py +++ b/iapws/iapws97.py @@ -3804,6 +3804,30 @@ def Region5_cp0(Tr: float, Pr: float) -> Tuple[float, float, float, float, float return go, gop, gopp, got, gott, gopt +def _solve_T_P(T: float, P: float) -> IAPWS97Properties: + """Solve for properties using T & P.""" + region = _Bound_TP(T, P) + if region == 1: + propiedades = _Region1(T, P) + elif region == 2: + propiedades = _Region2(T, P) + elif region == 3: + if T == Tc and P == Pc: + rho = rhoc + else: + vo = _Backward3_v_PT(P, T) + + def rho_funcion(rho: float) -> float: + return _Region3(rho, T).P-P + rho = float(newton(rho_funcion, 1/vo)) + propiedades = _Region3(rho, T) + elif region == 5: + propiedades = _Region5(T, P) + else: + raise NotImplementedError("Incoming out of bound") + return propiedades + + # Region definitions def _Bound_TP(T: float, P: float) -> Optional[int]: """Region definition for input T and P @@ -3846,6 +3870,50 @@ def _Bound_TP(T: float, P: float) -> Optional[int]: return region +def _solve_P_h(P: float, h: float) -> IAPWS97Properties: + """Solve for properties using P & h.""" + region = _Bound_Ph(P, h) + if region == 1: + To = _Backward1_T_Ph(P, h) + T = float(newton(lambda T: _Region1(T, P).h-h, To)) + propiedades = _Region1(T, P) + elif region == 2: + To = _Backward2_T_Ph(P, h) + T = float(newton(lambda T: _Region2(T, P).h-h, To)) + propiedades = _Region2(T, P) + elif region == 3: + vo = _Backward3_v_Ph(P, h) + To = _Backward3_T_Ph(P, h) + + def funcion(par: Tuple[float, float]) -> Tuple[float, float]: + return (_Region3(par[0], par[1]).h-h, + _Region3(par[0], par[1]).P-P) + rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) + propiedades = _Region3(rho, T) + elif region == 4: + T = _TSat_P(P) + if T <= 623.15: + h1 = _Region1(T, P).h + h2 = _Region2(T, P).h + x = (h-h1)/(h2-h1) + propiedades = _Region4(P, x) + else: + vo = _Backward3_v_Ph(P, h) + To = _Backward3_T_Ph(P, h) + + def funcion(par: Tuple[float, float]) -> Tuple[float, float]: + return (_Region3(par[0], par[1]).h-h, + _Region3(par[0], par[1]).P-P) + rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) + propiedades = _Region3(rho, T) + elif region == 5: + T = float(newton(lambda T: _Region5(T, P).h-h, 1500)) + propiedades = _Region5(T, P) + else: + raise NotImplementedError("Incoming out of bound") + return propiedades + + def _Bound_Ph(P: float, h: float) -> Optional[int]: """Region definition for input P y h @@ -3920,6 +3988,50 @@ def _Bound_Ph(P: float, h: float) -> Optional[int]: return region +def _solve_P_s(P: float, s: float) -> IAPWS97Properties: + """Solve for properties using P & s.""" + region = _Bound_Ps(P, s) + if region == 1: + To = _Backward1_T_Ps(P, s) + T = float(newton(lambda T: _Region1(T, P).s-s, To)) + propiedades = _Region1(T, P) + elif region == 2: + To = _Backward2_T_Ps(P, s) + T = float(newton(lambda T: _Region2(T, P).s-s, To)) + propiedades = _Region2(T, P) + elif region == 3: + vo = _Backward3_v_Ps(P, s) + To = _Backward3_T_Ps(P, s) + + def funcion(par: Tuple[float, float]) -> Tuple[float, float]: + return (_Region3(par[0], par[1]).s-s, + _Region3(par[0], par[1]).P-P) + rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) + propiedades = _Region3(rho, T) + elif region == 4: + T = _TSat_P(P) + if T <= 623.15: + s1 = _Region1(T, P).s + s2 = _Region2(T, P).s + x = (s-s1)/(s2-s1) + propiedades = _Region4(P, x) + else: + vo = _Backward3_v_Ps(P, s) + To = _Backward3_T_Ps(P, s) + + def funcion(par: Tuple[float, float]) -> Tuple[float, float]: + return (_Region3(par[0], par[1]).s-s, + _Region3(par[0], par[1]).P-P) + rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) + propiedades = _Region3(rho, T) + elif region == 5: + T = float(newton(lambda T: _Region5(T, P).s-s, 1500)) + propiedades = _Region5(T, P) + else: + raise NotImplementedError("Incoming out of bound") + return propiedades + + def _Bound_Ps(P: float, s: float) -> Optional[int]: """Region definition for input P and s @@ -3994,6 +4106,96 @@ def _Bound_Ps(P: float, s: float) -> Optional[int]: return region +def _solve_h_s(h: float, s: float) -> IAPWS97Properties: + """Solve for properties using h & s.""" + region = _Bound_hs(h, s) + if region == 1: + Po = _Backward1_P_hs(h, s) + To = _Backward1_T_Ph(Po, h) + + def funcion(par: Tuple[float, float]) -> Tuple[float, float]: + return (_Region1(par[0], par[1]).h-h, + _Region1(par[0], par[1]).s-s) + T, P = tuple(map(float, fsolve(funcion, [To, Po]))) + propiedades = _Region1(T, P) + elif region == 2: + Po = _Backward2_P_hs(h, s) + To = _Backward2_T_Ph(Po, h) + + def funcion(par: Tuple[float, float]) -> Tuple[float, float]: + return (_Region2(par[0], par[1]).h-h, + _Region2(par[0], par[1]).s-s) + T, P = tuple(map(float, fsolve(funcion, [To, Po]))) + propiedades = _Region2(T, P) + elif region == 3: + P = _Backward3_P_hs(h, s) + vo = _Backward3_v_Ph(P, h) + To = _Backward3_T_Ph(P, h) + + def funcion(par: Tuple[float, float]) -> Tuple[float, float]: + return (_Region3(par[0], par[1]).h-h, + _Region3(par[0], par[1]).s-s) + rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) + propiedades = _Region3(rho, T) + elif region == 4: + if round(s-sc, 6) == 0 and round(h-hc, 6) == 0: + propiedades = _Region3(rhoc, Tc) + + else: + To = _Backward4_T_hs(h, s) + if To < 273.15 or To > Tc: + To = 300 + + def funcion2(par: List[float]) -> Tuple[float, float]: + # This passes tests, but these assignments modify the CALLERS + # par tuple, instead of our copy. Was that intended? + if True: + if par[1] < 0: + par[1] = 0 + elif par[1] > 1: + par[1] = 1 + pp1 = par[1] + # And this does not. + else: + pp1 = par[1] + if pp1 < 0: + pp1 = 0 + elif pp1 > 1: + pp1 = 1 + + pp0 = par[0] + if pp0 < 273.15: + pp0 = 273.15 + elif pp0 > Tc: + pp0 = Tc + + Po = _PSat_T(pp0) + liquid = _Region1(pp0, Po) + vapor = _Region2(pp0, Po) + hl = liquid.h + sl = liquid.s + hv = vapor.h + sv = vapor.s + return (hv*pp1+hl*(1-pp1)-h, + sv*pp1+sl*(1-pp1)-s) + T, x = tuple(map(float, fsolve(funcion2, [To, 0.5]))) + P = _PSat_T(T) + + if Pt <= P < Pc and 0 < x < 1: + propiedades = _Region4(P, x) + elif Pt <= P <= Ps_623 and x == 0: + propiedades = _Region1(T, P) + elif region == 5: + def funcion(par: Tuple[float, float]) -> Tuple[float, float]: + return (_Region5(par[0], par[1]).h-h, + _Region5(par[0], par[1]).s-s) + T, P = tuple(map(float, fsolve(funcion, [1400, 1]))) + propiedades = _Region5(T, P) + else: + raise NotImplementedError("Incoming out of bound") + return propiedades + + def _Bound_hs(h: float, s: float) -> Optional[int]: """Region definition for input h and s @@ -4166,6 +4368,49 @@ def funcion(par: Tuple[float, float]) -> Tuple[float, float]: return region +def _solve_P_x(P: float, x: float) -> IAPWS97Properties: + """Solve for properties using P & x.""" + T = _TSat_P(P) + if Pt <= P < Pc and 0 < x < 1: + propiedades = _Region4(P, x) + elif Pt <= P <= Ps_623 and x == 0: + propiedades = _Region1(T, P) + elif Pt <= P <= Ps_623 and x == 1: + propiedades = _Region2(T, P) + elif Ps_623 < P < Pc and x in (0, 1): + def rho_funcion(rho: float) -> float: + return _Region3(rho, T).P-P + rhoo = 1./_Backward3_sat_v_P(P, T, int(x)) + rho = float(fsolve(rho_funcion, rhoo)[0]) + propiedades = _Region3(rho, T) + elif P == Pc and 0 <= x <= 1: + propiedades = _Region3(rhoc, Tc) + else: + raise NotImplementedError("Incoming out of bound") + propiedades.x = x + return propiedades + + +def _solve_T_x(T: float, x: float) -> IAPWS97Properties: + """Solve for properties using T & x.""" + P = _PSat_T(T) + if 273.15 <= T < Tc and 0 < x < 1: + propiedades = _Region4(P, x) + elif 273.15 <= T <= 623.15 and x == 0: + propiedades = _Region1(T, P) + elif 273.15 <= T <= 623.15 and x == 1: + propiedades = _Region2(T, P) + elif 623.15 < T < Tc and x in (0, 1): + rho = 1./_Backward3_sat_v_P(P, T, int(x)) + propiedades = _Region3(rho, T) + elif T == Tc and 0 <= x <= 1: + propiedades = _Region3(rhoc, Tc) + else: + raise NotImplementedError("Incoming out of bound") + propiedades.x = x + return propiedades + + def prop0(T: float, P: float) -> Dict[str, float]: """Ideal gas properties @@ -4313,12 +4558,12 @@ class IAPWS97(_fase): 1.8714 1.4098 2594.66 9.471 444.93 """ - kwargs = {"T": 0.0, - "P": 0.0, + kwargs = {"T": None, + "P": None, "x": None, "h": None, "s": None, - "v": 0.0, + "v": None, "l": 0.5893} status = 0 msg = "Unknown variables" @@ -4347,275 +4592,52 @@ def __call__(self, **kwargs) -> None: """Invoke the solver.""" self.kwargs.update(kwargs) - if self.calculable: - self.status = 1 - self.calculo() - self.msg = "Solved" + self.calculo() + self.msg = "Solved" @property - def calculable(self) -> str: + def calculable(self) -> bool: """Check if class is calculable by its kwargs""" - self._mode = "" - if self.kwargs["T"] and self.kwargs["P"]: - self._mode = "TP" - elif self.kwargs["P"] and self.kwargs["h"] is not None: - self._mode = "Ph" - elif self.kwargs["P"] and self.kwargs["s"] is not None: - self._mode = "Ps" - # TODO: Add other pairs definitions options - # elif self.kwargs["P"] and self.kwargs["v"]: - # self._mode = "Pv" - # elif self.kwargs["T"] and self.kwargs["s"] is not None: - # self._mode = "Ts" - elif self.kwargs["h"] is not None and self.kwargs["s"] is not None: - self._mode = "hs" - elif self.kwargs["T"] and self.kwargs["x"] is not None: - self._mode = "Tx" - elif self.kwargs["P"] and self.kwargs["x"] is not None: - self._mode = "Px" - return self._mode + return bool(self._calculable) def calculo(self) -> None: """Calculate procedure""" - arg1: float = self.kwargs[self._mode[0]] # type: ignore - arg2: float = self.kwargs[self._mode[1]] # type: ignore - args = (arg1, arg2) - if self._mode == "TP": - T, P = args - region = _Bound_TP(T, P) - if region == 1: - propiedades = _Region1(T, P) - elif region == 2: - propiedades = _Region2(T, P) - elif region == 3: - if T == Tc and P == Pc: - rho = rhoc - else: - vo = _Backward3_v_PT(P, T) - - def rho_funcion(rho: float) -> float: - assert(self.kwargs["T"] is not None) - return _Region3(rho, self.kwargs["T"]).P-P - rho = float(newton(rho_funcion, 1/vo)) - propiedades = _Region3(rho, T) - elif region == 5: - propiedades = _Region5(T, P) - else: - raise NotImplementedError("Incoming out of bound") - - elif self._mode == "Ph": - P, h = args - region = _Bound_Ph(P, h) - if region == 1: - To = _Backward1_T_Ph(P, h) - T = float(newton(lambda T: _Region1(T, P).h-h, To)) - propiedades = _Region1(T, P) - elif region == 2: - To = _Backward2_T_Ph(P, h) - T = float(newton(lambda T: _Region2(T, P).h-h, To)) - propiedades = _Region2(T, P) - elif region == 3: - vo = _Backward3_v_Ph(P, h) - To = _Backward3_T_Ph(P, h) - - def funcion(par: Tuple[float, float]) -> Tuple[float, float]: - return (_Region3(par[0], par[1]).h-h, - _Region3(par[0], par[1]).P-P) - rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) - propiedades = _Region3(rho, T) - elif region == 4: - T = _TSat_P(P) - if T <= 623.15: - h1 = _Region1(T, P).h - h2 = _Region2(T, P).h - x = (h-h1)/(h2-h1) - propiedades = _Region4(P, x) - else: - vo = _Backward3_v_Ph(P, h) - To = _Backward3_T_Ph(P, h) - - def funcion(par: Tuple[float, float]) -> Tuple[float, float]: - return (_Region3(par[0], par[1]).h-h, - _Region3(par[0], par[1]).P-P) - rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) - propiedades = _Region3(rho, T) - elif region == 5: - T = float(newton(lambda T: _Region5(T, P).h-h, 1500)) - propiedades = _Region5(T, P) - else: - raise NotImplementedError("Incoming out of bound") - - elif self._mode == "Ps": - P, s = args - region = _Bound_Ps(P, s) - if region == 1: - To = _Backward1_T_Ps(P, s) - T = float(newton(lambda T: _Region1(T, P).s-s, To)) - propiedades = _Region1(T, P) - elif region == 2: - To = _Backward2_T_Ps(P, s) - T = float(newton(lambda T: _Region2(T, P).s-s, To)) - propiedades = _Region2(T, P) - elif region == 3: - vo = _Backward3_v_Ps(P, s) - To = _Backward3_T_Ps(P, s) - - def funcion(par: Tuple[float, float]) -> Tuple[float, float]: - return (_Region3(par[0], par[1]).s-s, - _Region3(par[0], par[1]).P-P) - rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) - propiedades = _Region3(rho, T) - elif region == 4: - T = _TSat_P(P) - if T <= 623.15: - s1 = _Region1(T, P).s - s2 = _Region2(T, P).s - x = (s-s1)/(s2-s1) - propiedades = _Region4(P, x) - else: - vo = _Backward3_v_Ps(P, s) - To = _Backward3_T_Ps(P, s) - - def funcion(par: Tuple[float, float]) -> Tuple[float, float]: - return (_Region3(par[0], par[1]).s-s, - _Region3(par[0], par[1]).P-P) - rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) - propiedades = _Region3(rho, T) - elif region == 5: - T = float(newton(lambda T: _Region5(T, P).s-s, 1500)) - propiedades = _Region5(T, P) - else: - raise NotImplementedError("Incoming out of bound") - - elif self._mode == "hs": - h, s = args - region = _Bound_hs(h, s) - if region == 1: - Po = _Backward1_P_hs(h, s) - To = _Backward1_T_Ph(Po, h) - - def funcion(par: Tuple[float, float]) -> Tuple[float, float]: - return (_Region1(par[0], par[1]).h-h, - _Region1(par[0], par[1]).s-s) - T, P = tuple(map(float, fsolve(funcion, [To, Po]))) - propiedades = _Region1(T, P) - elif region == 2: - Po = _Backward2_P_hs(h, s) - To = _Backward2_T_Ph(Po, h) - - def funcion(par: Tuple[float, float]) -> Tuple[float, float]: - return (_Region2(par[0], par[1]).h-h, - _Region2(par[0], par[1]).s-s) - T, P = tuple(map(float, fsolve(funcion, [To, Po]))) - propiedades = _Region2(T, P) - elif region == 3: - P = _Backward3_P_hs(h, s) - vo = _Backward3_v_Ph(P, h) - To = _Backward3_T_Ph(P, h) - - def funcion(par: Tuple[float, float]) -> Tuple[float, float]: - return (_Region3(par[0], par[1]).h-h, - _Region3(par[0], par[1]).s-s) - rho, T = tuple(map(float, fsolve(funcion, [1/vo, To]))) - propiedades = _Region3(rho, T) - elif region == 4: - if round(s-sc, 6) == 0 and round(h-hc, 6) == 0: - propiedades = _Region3(rhoc, Tc) - - else: - To = _Backward4_T_hs(h, s) - if To < 273.15 or To > Tc: - To = 300 - - def funcion2(par: List[float]) -> Tuple[float, float]: - # This passes tests, but these assignments modify the CALLERS - # par tuple, instead of our copy. Was that intended? - if True: - if par[1] < 0: - par[1] = 0 - elif par[1] > 1: - par[1] = 1 - pp1 = par[1] - # And this does not. - else: - pp1 = par[1] - if pp1 < 0: - pp1 = 0 - elif pp1 > 1: - pp1 = 1 - - pp0 = par[0] - if pp0 < 273.15: - pp0 = 273.15 - elif pp0 > Tc: - pp0 = Tc - - Po = _PSat_T(pp0) - liquid = _Region1(pp0, Po) - vapor = _Region2(pp0, Po) - hl = liquid.h - sl = liquid.s - hv = vapor.h - sv = vapor.s - return (hv*pp1+hl*(1-pp1)-h, - sv*pp1+sl*(1-pp1)-s) - T, x = tuple(map(float, fsolve(funcion2, [To, 0.5]))) - P = _PSat_T(T) - - if Pt <= P < Pc and 0 < x < 1: - propiedades = _Region4(P, x) - elif Pt <= P <= Ps_623 and x == 0: - propiedades = _Region1(T, P) - elif region == 5: - def funcion(par: Tuple[float, float]) -> Tuple[float, float]: - return (_Region5(par[0], par[1]).h-h, - _Region5(par[0], par[1]).s-s) - T, P = tuple(map(float, fsolve(funcion, [1400, 1]))) - propiedades = _Region5(T, P) - else: - raise NotImplementedError("Incoming out of bound") - - elif self._mode == "Px": - P, x = args - T = _TSat_P(P) - if Pt <= P < Pc and 0 < x < 1: - propiedades = _Region4(P, x) - elif Pt <= P <= Ps_623 and x == 0: - propiedades = _Region1(T, P) - elif Pt <= P <= Ps_623 and x == 1: - propiedades = _Region2(T, P) - elif Ps_623 < P < Pc and x in (0, 1): - def rho_funcion(rho: float) -> float: - return _Region3(rho, T).P-P - rhoo = 1./_Backward3_sat_v_P(P, T, int(x)) - rho = float(fsolve(rho_funcion, rhoo)[0]) - propiedades = _Region3(rho, T) - elif P == Pc and 0 <= x <= 1: - propiedades = _Region3(rhoc, Tc) - else: - raise NotImplementedError("Incoming out of bound") - self.sigma = _Tension(T) - propiedades.x = x + T = self.kwargs["T"] + P = self.kwargs["P"] + h = self.kwargs["h"] + s = self.kwargs["s"] + x = self.kwargs["x"] + + self.status = 0 + self._calculable = False + if T is not None and P is not None: + propiedades = _solve_T_P(T, P) + elif P is not None and h is not None: + propiedades = _solve_P_h(P, h) + elif P is not None and s is not None: + propiedades = _solve_P_s(P, s) + # TODO: Add other pairs definitions options + # elif P is not None and v is not None: + # propiedades = self.solve_P_v(P, v) + # elif T is not None and s is not None: + # propiedades = self.solve_T_s(T, s) + elif h is not None and s is not None: + propiedades = _solve_h_s(h, s) + elif P is not None and x is not None: + propiedades = _solve_P_x(P, x) + self.sigma = _Tension(propiedades.T) + elif T is not None and x is not None: + propiedades = _solve_T_x(T, x) + self.sigma = _Tension(propiedades.T) + else: + return - elif self._mode == "Tx": - T, x = args - P = _PSat_T(T) - if 273.15 <= T < Tc and 0 < x < 1: - propiedades = _Region4(P, x) - elif 273.15 <= T <= 623.15 and x == 0: - propiedades = _Region1(T, P) - elif 273.15 <= T <= 623.15 and x == 1: - propiedades = _Region2(T, P) - elif 623.15 < T < Tc and x in (0, 1): - rho = 1./_Backward3_sat_v_P(P, T, int(x)) - propiedades = _Region3(rho, T) - elif T == Tc and 0 <= x <= 1: - propiedades = _Region3(rhoc, Tc) - else: - raise NotImplementedError("Incoming out of bound") - self.sigma = _Tension(T) - propiedades.x = x + self.dofill(propiedades) + def dofill(self, propiedades: IAPWS97Properties) -> None: + """Finish filling the class.""" + self.status = 1 + self._calculable = True self.M = 18.015257 # kg/kmol self.Pc = Pc self.Tt = Tt