From 6d162455ded86e4a28870c4d59c90af27da09955 Mon Sep 17 00:00:00 2001 From: HugoMVale <57530119+HugoMVale@users.noreply.github.com> Date: Sat, 14 Oct 2023 16:24:50 +0200 Subject: [PATCH] refactor pvtpolymer, add Hartmann-Haque --- src/polykin/physprops/__init__.py | 2 +- src/polykin/physprops/property_equation.py | 9 +- .../physprops/{tait.py => pvtpolymer.py} | 392 ++++++++++++++---- tests/physprops/test_pvtpolymer.py | 150 +++++++ tests/physprops/test_tait.py | 105 ----- 5 files changed, 474 insertions(+), 184 deletions(-) rename src/polykin/physprops/{tait.py => pvtpolymer.py} (54%) create mode 100644 tests/physprops/test_pvtpolymer.py delete mode 100644 tests/physprops/test_tait.py diff --git a/src/polykin/physprops/__init__.py b/src/polykin/physprops/__init__.py index e74948a..75efee7 100644 --- a/src/polykin/physprops/__init__.py +++ b/src/polykin/physprops/__init__.py @@ -11,5 +11,5 @@ """ from polykin.physprops.dippr import * -from polykin.physprops.tait import * +from polykin.physprops.pvtpolymer import * from polykin.physprops.vapor_pressure import * diff --git a/src/polykin/physprops/property_equation.py b/src/polykin/physprops/property_equation.py index 99e9195..e7b1d0c 100644 --- a/src/polykin/physprops/property_equation.py +++ b/src/polykin/physprops/property_equation.py @@ -27,15 +27,11 @@ def __init__(self, symbol: str, name: str ) -> None: + """Construct `PropertyEquation` with the given inputs.""" self.unit = unit self.symbol = symbol self.name = name - @abstractmethod - def __call__(self, *args) -> FloatOrArray: - """Evaluate property equation, $Y(...)$.""" - pass - class PropertyEquationT(PropertyEquation): r"""_Abstract_ temperature-dependent property equation, $p(T)$""" @@ -52,6 +48,7 @@ def __init__(self, symbol: str, name: str ) -> None: + """Construct `PropertyEquationT` with the given inputs.""" check_bounds(Trange[0], 0, np.inf, 'Tmin') check_bounds(Trange[1], 0, np.inf, 'Tmax') @@ -86,7 +83,7 @@ def __call__(self, @staticmethod @abstractmethod def equation(T: FloatOrArray, *args) -> FloatOrArray: - """Property equation, $Y(T,p)$.""" + """Property equation, $Y(T,p...)$.""" pass def __repr__(self) -> str: diff --git a/src/polykin/physprops/tait.py b/src/polykin/physprops/pvtpolymer.py similarity index 54% rename from src/polykin/physprops/tait.py rename to src/polykin/physprops/pvtpolymer.py index dcda71b..d021177 100644 --- a/src/polykin/physprops/tait.py +++ b/src/polykin/physprops/pvtpolymer.py @@ -5,7 +5,7 @@ from __future__ import annotations from polykin.utils import check_bounds, convert_check_temperature, \ - convert_check_pressure, \ + convert_check_pressure, vectorize, \ FloatOrArray, FloatOrArrayLike, eps from polykin.physprops.property_equation import PropertyEquation @@ -17,7 +17,7 @@ from scipy.optimize import root_scalar -__all__ = ['Tait'] +__all__ = ['Tait', 'Flory', 'HartmannHaque'] # %% Parameter tables @@ -34,15 +34,15 @@ def load_Tait_parameters() -> pd.DataFrame: return table_Tait_parameters -# %% PolymerEoS +# %% PolymerPVTEquation -class PolymerEoS(PropertyEquation): - r"""_Abstract_ polymer equation of state, $V(T, P)$""" +class PolymerPVTEquation(PropertyEquation): + r"""_Abstract_ polymer PVT equation, $\hat{V}(T, P)$""" Trange: tuple[FloatOrArray, FloatOrArray] Prange: tuple[FloatOrArray, FloatOrArray] symbol = r"$\hat{V}$" - unit = "kg/m³" + unit = "m³/kg" def __init__(self, Tmin: float, @@ -64,13 +64,13 @@ def __init__(self, self.Prange = (Pmin, Pmax) self.name = name - def __call__(self, - T: FloatOrArrayLike, - P: FloatOrArrayLike, - Tunit: Literal['C', 'K'] = 'K', - Punit: Literal['bar', 'MPa', 'Pa'] = 'Pa' - ) -> FloatOrArray: - r"""Evaluate specific volume, $\hat{V}$, at given temperature and + def V(self, + T: FloatOrArrayLike, + P: FloatOrArrayLike, + Tunit: Literal['C', 'K'] = 'K', + Punit: Literal['bar', 'MPa', 'Pa'] = 'Pa' + ) -> FloatOrArray: + r"""Evaluate the specific volume, $\hat{V}$, at given temperature and pressure, including unit conversion and range check. Parameters @@ -90,7 +90,7 @@ def __call__(self, ------- FloatOrArray Specific volume. - Unit = m³/kg + Unit = m³/kg. """ TK = convert_check_temperature(T, Tunit, self.Trange) Pa = convert_check_pressure(P, Punit, self.Prange) @@ -118,10 +118,182 @@ def eval(self, T: FloatOrArray, P: FloatOrArray) -> FloatOrArray: """ pass + @abstractmethod + def alpha(self, T: FloatOrArray, P: FloatOrArray) -> FloatOrArray: + r"""Calculate thermal expansion coefficient, $\alpha$. + + $$\alpha=\frac{1}{V}\left(\frac{\partial V}{\partial T}\right)_{P}$$ + + Parameters + ---------- + T : FloatOrArray + Temperature. + Unit = K. + P : FloatOrArray + Pressure. + Unit = Pa. + + Returns + ------- + FloatOrArray + Thermal expansion coefficient, $\alpha$. + """ + pass + + @abstractmethod + def beta(self, T: FloatOrArray, P: FloatOrArray) -> FloatOrArray: + r"""Calculate isothermal compressibility coefficient, $\beta$. + + $$\beta=-\frac{1}{V}\left(\frac{\partial V}{\partial P}\right)_{T}$$ + + Parameters + ---------- + T : FloatOrArray + Temperature. + Unit = K. + P : FloatOrArray + Pressure. + Unit = Pa. + + Returns + ------- + FloatOrArray + Isothermal compressibility coefficient, $\beta$. + """ + pass + +# %% PolymerPVTEoS + + +class PolymerPVTEoS(PolymerPVTEquation): + r"""_Abstract_ polymer equation of state in reduced form, + $V(T, P, V0, T0, P0)$.""" + + def __init__(self, + V0: float, + T0: float, + P0: float, + Tmin: float = 0.0, + Tmax: float = np.inf, + Pmin: float = 0.0, + Pmax: float = np.inf, + name: str = '' + ) -> None: + """Construct `PolymerEoSReduced` with the given parameters.""" + + # Check bounds + check_bounds(V0, 0, np.inf, 'V0') + check_bounds(T0, 0, np.inf, 'T0') + check_bounds(P0, 0, np.inf, 'P0') + + self.V0 = V0 + self.T0 = T0 + self.P0 = P0 + super().__init__(Tmin, Tmax, Pmin, Pmax, name) + + @vectorize + def eval(self, + T: FloatOrArray, + P: FloatOrArray + ) -> FloatOrArray: + t = T/self.T0 + p = P/self.P0 + solution = root_scalar(f=self.equation, + args=(t, p), + # bracket=[1.1, 1.5], + x0=1.1, + method='halley', + fprime=True, + fprime2=True) + + if solution.converged: + v = solution.root + V = v*self.V0 + else: + print(solution.flag) + V = -1. + return V + + def alpha(self, + T: FloatOrArray, + P: FloatOrArray + ) -> FloatOrArray: + r"""Calculate thermal expansion coefficient, $\alpha$. + + $$\alpha=\frac{1}{V}\left(\frac{\partial V}{\partial T}\right)_{P}$$ + + Parameters + ---------- + T : FloatOrArray + Temperature. + Unit = K. + P : FloatOrArray + Pressure. + Unit = Pa. + + Returns + ------- + FloatOrArray + Thermal expansion coefficient, $\alpha$. + """ + dT = 0.5 + V2 = self.eval(T + dT, P) + V1 = self.eval(T - dT, P) + return (V2 - V1)/dT/(V1 + V2) + + def beta(self, + T: FloatOrArray, + P: FloatOrArray + ) -> FloatOrArray: + r"""Calculate isothermal compressibility coefficient, $\beta$. + + $$\beta=-\frac{1}{V}\left(\frac{\partial V}{\partial P}\right)_{T}$$ + + Parameters + ---------- + T : FloatOrArray + Temperature. + Unit = K. + P : FloatOrArray + Pressure. + Unit = Pa. + + Returns + ------- + FloatOrArray + Isothermal compressibility coefficient, $\beta$. + """ + dP = 1e5 + P2 = P + dP + P1 = np.max(P - dP, 0) + V2 = self.eval(T, P2) + V1 = self.eval(T, P1) + return -(V2 - V1)/(P2 - P1)/(V1 + V2)*2 + + @staticmethod + @abstractmethod + def equation(v: float, t: float, p: float) -> tuple[float, ...]: + """Equation of state and its volume derivatives. + + Parameters + ---------- + v : float + Reduced volume. + t : float + Reduced temperature. + p : float + Reduced pressure. + + Returns + ------- + tuple[float,...] + Equation of state, first derivative, second derivative. + """ + pass # %% Tait -class Tait(PolymerEoS): +class Tait(PolymerPVTEquation): r"""Tait equation of state for the specific volume of a liquid. This EoS implements the following temperature and pressure dependence: @@ -146,19 +318,19 @@ class Tait(PolymerEoS): ---------- A0 : float Parameter of equation. - Unit = m³/kg + Unit = m³/kg. A1 : float Parameter of equation. - Unit = m³/(kg.K) + Unit = m³/(kg·K). A2 : float Parameter of equation. - Unit = m³/(kg.K²) + Unit = m³/(kg·K²). B0 : float Parameter of equation. - Unit = Pa + Unit = Pa. B1 : float Parameter of equation. - Unit = 1/K + Unit = 1/K. Tmin : float Lower temperature bound. Unit = K. @@ -167,10 +339,10 @@ class Tait(PolymerEoS): Unit = K. Pmin : float Lower pressure bound. - Unit = Pa + Unit = Pa. Pmax : float Upper pressure bound. - Unit = Pa + Unit = Pa. name : str Name. """ @@ -216,13 +388,13 @@ def __repr__(self) -> str: f"name: {self.name}\n" f"symbol: {self.symbol}\n" f"unit: {self.unit}\n" + f"Trange [K]: {self.Trange}\n" + f"Prange [Pa]: {self.Prange}\n" f"A0 [m³/kg]: {self.A0}\n" f"A1 [m³/kg.K]: {self.A1}\n" f"A2 [m³/kg.K²]: {self.A2}\n" f"B0 [Pa]: {self.B0}\n" - f"B1 [1/K]: {self.B1}\n" - f"Trange [K]: {self.Trange}\n" - f"Prange [Pa]: {self.Prange}" + f"B1 [1/K]: {self.B1}" ) def eval(self, @@ -333,8 +505,6 @@ def from_database(cls, name: str) -> Optional[Tait]: The parameters are those reported in Table 3B-1 (p. 41) of the Handbook of Polymer Solution Thermodynamics. - - Parameters ---------- name : str @@ -355,56 +525,134 @@ def from_database(cls, name: str) -> Optional[Tait]: parameters['Pmax'] *= 1e6 return cls(**parameters, name=name) -# %% FloryEoS +# %% Flory -class FloryEoS(PolymerEoS): +class Flory(PolymerPVTEoS): + r"""Flory equation of state for the specific volume of a polymer. - def __init__(self, - V0: float, - T0: float, - P0: float, - Tmin: float = 0.0, - Tmax: float = np.inf, - Pmin: float = 0.0, - Pmax: float = np.inf, - name: str = '' - ) -> None: - """Construct `FloryEoS` with the given parameters.""" + This EoS implements the following implicit P-V-T dependence: - # Check bounds - check_bounds(V0, 0, np.inf, 'V0') - check_bounds(T0, 0, np.inf, 'T0') - check_bounds(P0, 0, np.inf, 'P0') + $$ \frac{\tilde{P}\tilde{V}}{\tilde{T}} = \\ + \frac{\tilde{V}^{1/3}}{\tilde{V}^{1/3}-1}-\frac{1}{\tilde{V}\tilde{T}}$$ - self.V0 = V0 - self.T0 = T0 - self.P0 = P0 - super().__init__(Tmin, Tmax, Pmin, Pmax, name) + where $\tilde{V}=V/V^*$, $\tilde{P}=P/P^*$ and $\tilde{T}=T/T^*$ are, + respectively, the reduced volume, reduced pressure and reduced temperature. + $V^*$, $P^*$ and $T^*$ are reference quantities that are polymer dependent. - def eval(self, T, P): - t = T/self.T0 - p = P/self.P0 - solution = root_scalar(f=self._eos, - args=(t, p), - # bracket=[1.1, 1.5], - x0=1.1, - method='newton', - fprime=True - ) - # x0=1.2, - # fprime=True) - if solution.converged: - v = solution.root - V = v*self.V0 - else: - print(solution.flag) - V = -1. - return V + References: - def _eos(self, v: float, t: float, p: float) -> tuple[float, float]: - f = p*v/t - (v**(1/3)/(v**(1/3) - 1) - 1/(v*t)) - # return f - df = p/t - 1/(t*v**2) - 1/(3*(v**(1/3) - 1)*v**(2/3)) + \ + * Caruthers et al. Handbook of Diffusion and Thermal Properties of + Polymers and Polymer Solutions. AIChE, 1998. + + Parameters + ---------- + V0 : float + Reference volume, $V^*$. + T0 : float + Reference temperature, $T^*$. + P0 : float + Reference pressure, $P^*$. + Tmin : float + Lower temperature bound. + Unit = K. + Tmax : float + Upper temperature bound. + Unit = K. + Pmin : float + Lower pressure bound. + Unit = Pa. + Pmax : float + Upper pressure bound. + Unit = Pa. + name : str + Name. + """ + + @staticmethod + def equation(v: float, t: float, p: float) -> tuple[float, float, float]: + r"""Flory equation of state and its volume derivatives. + + Parameters + ---------- + v : float + Reduced volume, $\tilde{V}$. + t : float + Reduced temperature, $\tilde{T}$. + p : float + Reduced pressure, $\tilde{P}$. + + Returns + ------- + tuple[float, float, float] + Equation of state, first derivative, second derivative. + """ + f = p*v/t - (v**(1/3)/(v**(1/3) - 1) - 1/(v*t)) # =0 + d1f = p/t - 1/(t*v**2) - 1/(3*(v**(1/3) - 1)*v**(2/3)) + \ 1/(3*(v**(1/3) - 1)**2*v**(1/3)) - return (f, df) + d2f = (2*(9/t + (v**(4/3) - 2*v**(5/3))/(-1 + v**(1/3))**3))/(9*v**3) + return (f, d1f, d2f) + + +class HartmannHaque(PolymerPVTEoS): + r"""Hartmann-Haque equation of state for the specific volume of a polymer. + + This EoS implements the following implicit P-V-T dependence: + + $$ \tilde{P}\tilde{V}^5=\tilde{T}^{3/2}-\ln{\tilde{V}} $$ + + where $\tilde{V}=V/V^*$, $\tilde{P}=P/P^*$ and $\tilde{T}=T/T^*$ are, + respectively, the reduced volume, reduced pressure and reduced temperature. + $V^*$, $P^*$ and $T^*$ are reference quantities that are polymer dependent. + + References: + + * Caruthers et al. Handbook of Diffusion and Thermal Properties of + Polymers and Polymer Solutions. AIChE, 1998. + + Parameters + ---------- + V0 : float + Reference volume, $V^*$. + T0 : float + Reference temperature, $T^*$. + P0 : float + Reference pressure, $P^*$. + Tmin : float + Lower temperature bound. + Unit = K. + Tmax : float + Upper temperature bound. + Unit = K. + Pmin : float + Lower pressure bound. + Unit = Pa. + Pmax : float + Upper pressure bound. + Unit = Pa. + name : str + Name. + """ + + @staticmethod + def equation(v: float, t: float, p: float) -> tuple[float, float, float]: + """Hartmann-Haque equation of state and its volume derivatives. + + Parameters + ---------- + v : float + Reduced volume. + t : float + Reduced temperature. + p : float + Reduced pressure. + + Returns + ------- + tuple[float, float, float] + Equation of state, first derivative, second derivative. + """ + f = p*v**5 - t**(3/2) + np.log(v) # =0 + d1f = 5*p*v**4 + 1/v + d2f = 20*p*v**3 - 1/v**2 + return (f, d1f, d2f) diff --git a/tests/physprops/test_pvtpolymer.py b/tests/physprops/test_pvtpolymer.py new file mode 100644 index 0000000..4da1533 --- /dev/null +++ b/tests/physprops/test_pvtpolymer.py @@ -0,0 +1,150 @@ +# PolyKin: A polymerization kinetics library for Python. +# +# Copyright Hugo Vale 2023 + +from polykin.physprops.pvtpolymer import Tait, Flory, HartmannHaque +from polykin.utils import RangeError +from polykin.physprops.pvtpolymer import load_Tait_parameters + + +import pytest +import numpy as np + +atol = 0e0 +rtol = 1e-4 + +# %% Tait + + +@pytest.fixture +def tait_instance(): + return Tait( + A0=8.2396e-4, + A1=3.0490e-7, + A2=7.0201e-10, + B0=2.9803e8, + B1=4.3789e-3, + Tmin=387.15, + Tmax=432.15, + Pmin=0.1e6, + Pmax=200e6, + name="Example Handbook Polymer Solution Thermodynamics, p.39" + ) + + +def test_Tait_input_validation(tait_instance, capsys): + with pytest.raises(ValueError): + _ = Tait(1., 3e-7, 7e-10, 2e8, 4e-3) + with pytest.raises(ValueError): + _ = Tait(8e-4, 6e4, 7e-10, 2e8, 4e-3) + with pytest.raises(ValueError): + _ = Tait(8e-4, 3e-7, 1e-6, 2e8, 4e-3) + with pytest.raises(ValueError): + _ = Tait(8e-4, 3e-7, 7e-10, 178, 4e-3) + with pytest.raises(ValueError): + _ = Tait(8e-4, 3e-7, 7e-10, 2e8, 1) + with pytest.raises(RangeError): + _ = tait_instance.V(-1, 1, Tunit='K') + with pytest.raises(RangeError): + _ = tait_instance.V(1, -1, Tunit='K') + + +def test_Tait_Trange_warning(tait_instance, capsys): + _ = tait_instance.V(450, 10, Tunit='K') + out, _ = capsys.readouterr() + assert (out.lower().startswith('warning')) + + +def test_Tait_Prange_warning(tait_instance, capsys): + _ = tait_instance.V(400, 2010, Tunit='K', Punit='bar') + out, _ = capsys.readouterr() + assert (out.lower().startswith('warning')) + + +def test_Tait_repr(tait_instance): + out = tait_instance.__repr__() + assert out.startswith('name') + + +def test_Tait_V0(tait_instance): + V0 = tait_instance.eval(432.15, 0) + assert np.isclose(V0, 8.9019e-4, atol=atol, rtol=rtol) + + +def test_Tait_B(tait_instance): + B = tait_instance._B(432.15) + assert np.isclose(B, 1.4855e8, atol=atol, rtol=rtol) + + +def test_Tait_eval(tait_instance): + V = tait_instance.eval(432.15, 2e8) + assert np.isclose(V, 8.2232e-4, atol=atol, rtol=rtol) + + +def test_Tait_V(tait_instance): + V = tait_instance.V(159., 2000, Tunit='C', Punit='bar') + assert np.isclose(V, 8.2232e-4, atol=atol, rtol=rtol) + + +def test_Tait_alpha(tait_instance): + alpha = tait_instance.alpha(432.15, 2e8) + assert np.isclose(alpha, 3.5012e-4, atol=atol, rtol=rtol) + + +def test_Tait_beta(tait_instance): + beta = tait_instance.beta(432.15, 2e8) + assert np.isclose(beta, 2.7765e-10, atol=atol, rtol=rtol) + + +def test_Tait_all_polymers_database(): + table = load_Tait_parameters() + polymers = table.index.to_list() + for polymer in polymers: + m = Tait.from_database(polymer) + assert m is not None + rhoP = 1/m.eval(298., 1e5) + assert (rhoP > 750. and rhoP < 2200.) + +# %% Flory + + +@pytest.fixture +def flory_instance(): + return Flory( + 0.9455e-3, 7396., 396e6, + name="Handbook of diffusion and thermal properties.., , p. 93.") + + +def test_Flory_V(flory_instance): + "Handbook of diffusion and thermal properties.., , p. 93." + assert np.isclose(flory_instance.V(335., 70, Punit='MPa'), + 1.0753e-3, atol=0, rtol=2e-4) + + +def test_Flory_alpha(flory_instance): + "Handbook of diffusion and thermal properties.., , p. 93." + assert np.isclose(flory_instance.alpha(335., 70e6), + 4.2779e-4, atol=0, rtol=2e-3) + + +# %% HartmannHaque + + +@pytest.fixture +def HartmannHaque_instance(): + return HartmannHaque( + V0=0.9935e-3, T0=1422., P0=2976e6, + name="Handbook of diffusion and thermal properties.., , p. 85.") + + +def test_HartmannHaque_V(HartmannHaque_instance): + "Handbook of diffusion and thermal properties.., , p. 85." + m = HartmannHaque_instance + assert np.isclose(m.V(335., 70, Punit='MPa'), + 1.0756e-3, atol=0, rtol=2e-4) + + +def test_HartmannHaque_alpha(HartmannHaque_instance): + m = HartmannHaque_instance + assert np.isclose(m.alpha(335., 70e6), + 4.3e-4, atol=0, rtol=2e-2) diff --git a/tests/physprops/test_tait.py b/tests/physprops/test_tait.py deleted file mode 100644 index 14b6d6d..0000000 --- a/tests/physprops/test_tait.py +++ /dev/null @@ -1,105 +0,0 @@ -# PolyKin: A polymerization kinetics library for Python. -# -# Copyright Hugo Vale 2023 - -from polykin.physprops.tait import Tait -from polykin.utils import RangeError -from polykin.physprops.tait import load_Tait_parameters - - -import pytest -import numpy as np - - -@pytest.fixture -def tait_instance(): - return Tait( - A0=8.2396e-4, - A1=3.0490e-7, - A2=7.0201e-10, - B0=2.9803e8, - B1=4.3789e-3, - Tmin=387.15, - Tmax=432.15, - Pmin=0.1e6, - Pmax=200e6, - name="Example Handbook Polymer Solution Thermodynamics, p.39" - ) - - -atol = 0e0 -rtol = 1e-4 - - -def test_input_validation(tait_instance, capsys): - with pytest.raises(ValueError): - _ = Tait(1., 3e-7, 7e-10, 2e8, 4e-3) - with pytest.raises(ValueError): - _ = Tait(8e-4, 6e4, 7e-10, 2e8, 4e-3) - with pytest.raises(ValueError): - _ = Tait(8e-4, 3e-7, 1e-6, 2e8, 4e-3) - with pytest.raises(ValueError): - _ = Tait(8e-4, 3e-7, 7e-10, 178, 4e-3) - with pytest.raises(ValueError): - _ = Tait(8e-4, 3e-7, 7e-10, 2e8, 1) - with pytest.raises(RangeError): - _ = tait_instance.__call__(-1, 1, Tunit='K') - with pytest.raises(RangeError): - _ = tait_instance.__call__(1, -1, Tunit='K') - - -def test_Trange_warning(tait_instance, capsys): - _ = tait_instance.__call__(450, 10, Tunit='K') - out, _ = capsys.readouterr() - assert (out.lower().startswith('warning')) - - -def test_Prange_warning(tait_instance, capsys): - _ = tait_instance.__call__(400, 2010, Tunit='K', Punit='bar') - out, _ = capsys.readouterr() - assert (out.lower().startswith('warning')) - - -def test_repr(tait_instance): - out = tait_instance.__repr__() - assert out.startswith('name') - - -def test_V0(tait_instance): - V0 = tait_instance.eval(432.15, 0) - assert np.isclose(V0, 8.9019e-4, atol=atol, rtol=rtol) - - -def test_B(tait_instance): - B = tait_instance._B(432.15) - assert np.isclose(B, 1.4855e8, atol=atol, rtol=rtol) - - -def test_V_eval(tait_instance): - V = tait_instance.eval(432.15, 2e8) - assert np.isclose(V, 8.2232e-4, atol=atol, rtol=rtol) - - -def test_V_call(tait_instance): - V = tait_instance(159., 2000, Tunit='C', Punit='bar') - assert np.isclose(V, 8.2232e-4, atol=atol, rtol=rtol) - - -def test_alpha(tait_instance): - alpha = tait_instance.alpha(432.15, 2e8) - assert np.isclose(alpha, 3.5012e-4, atol=atol, rtol=rtol) - - -def test_beta(tait_instance): - beta = tait_instance.beta(432.15, 2e8) - assert np.isclose(beta, 2.7765e-10, atol=atol, rtol=rtol) - - -def test_all_polymers_database(): - table = load_Tait_parameters() - polymers = table.index.to_list() - for polymer in polymers: - m = Tait.from_database(polymer) - assert m is not None - rhoP = 1/m.eval(298., 1e5) - assert (rhoP > 750. and rhoP < 2200.)