diff --git a/interfaces/cython/cantera/test/test_purefluid.py b/interfaces/cython/cantera/test/test_purefluid.py index 5ddc6e842..610185b3a 100644 --- a/interfaces/cython/cantera/test/test_purefluid.py +++ b/interfaces/cython/cantera/test/test_purefluid.py @@ -1,7 +1,14 @@ +from __future__ import division + +import itertools +import numpy as np + import cantera as ct from . import utilities + class TestPureFluid(utilities.CanteraTest): + """ Test functionality of the PureFluid class """ def setUp(self): self.water = ct.Water() @@ -52,3 +59,362 @@ class TestPureFluid(utilities.CanteraTest): def test_properties_near_max(self): self.check_fd_properties(self.water.max_temp*(1-1e-5), 101325, self.water.max_temp*(1-1e-4), 101325, 1e-2) + + +# To minimize errors when transcribing tabulated data, the input units here are: +# T: K, P: MPa, rho: kg/m3, v: m3/kg, (u,h): kJ/kg, s: kJ/kg-K +# Which are then converted to SI +class StateData(object): + def __init__(self, phase, T, p, rho=None, v=None, u=None, h=None, s=None, relax=False): + self.phase = phase + self.T = T + self.p = p * 1e6 + self.rho = rho if rho else 1.0/v + self.u = 1e3 * u if u is not None else 1e3 * h - self.p/self.rho + self.s = 1e3 * s + self.tolMod = 10.0 if relax else 1.0 + + +class Tolerances(object): + def __init__(self, p=None, u=None, s=None, + dUdS=None, dAdV=None, dPdT=None, hTs=None): + self.p = p or 2e-5 + self.u = u or 2e-6 + self.s = s or 2e-6 + self.dUdS = dUdS or 2e-6 + self.dAdV = dAdV or 2e-6 + self.dPdT = dPdT or 2e-4 + self.hTs = hTs or 2e-4 + + +class PureFluidTestCases(object): + """ + Test the results of pure fluid phase calculations against tabulated + references and for consistency with basic thermodynamic relations. + """ + fluids = {} + + def __init__(self, name, refState, tolerances=Tolerances()): + if name not in self.fluids: + self.fluids[name] = ct.PureFluid('liquidvapor.xml', name) + + self.fluid = self.fluids[name] + + self.fluid.TD = refState.T, refState.rho + self.refState = refState + self.u0 = self.fluid.u + self.s0 = self.fluid.s + self.tol = tolerances + + def a(self, T, rho): + """ Helmholtz free energy """ + self.fluid.TD = T, rho + return self.fluid.u - T * self.fluid.s + + def test_consistency_temperature(self): + for state in self.states: + dT = 2e-5 * state.T + self.fluid.TD = state.T-dT, state.rho + s1 = self.fluid.s + u1 = self.fluid.u + self.fluid.TD = state.T+dT, state.rho + s2 = self.fluid.s + u2 = self.fluid.u + + # At constant volume, dU = T dS + msg = 'At state: T=%s, rho=%s' % (state.T, state.rho) + self.assertNear((u2-u1)/(s2-s1), state.T, self.tol.dUdS, msg=msg) + + def test_consistency_volume(self): + for state in self.states: + self.fluid.TD = state.T, state.rho + p = self.fluid.P + V = 1 / state.rho + dV = 5e-6 * V + + a1 = self.a(state.T, 1/(V-0.5*dV)) + a2 = self.a(state.T, 1/(V+0.5*dV)) + + # dP/drho is high for liquids, so relax tolerances + tol = 100 *self.tol.dAdV if state.phase == 'liquid' else self.tol.dAdV + + # At constant temperature, dA = - p dV + msg = 'At state: T=%s, rho=%s' % (state.T, state.rho) + self.assertNear(-(a2-a1)/dV, p, tol, msg=msg) + + def test_saturation(self): + for state in self.states: + if state.phase == 'super': + continue + + dT = 1e-6 * state.T + self.fluid.TX = state.T, 0 + p1 = self.fluid.P + vf = 1.0 / self.fluid.density + hf = self.fluid.h + sf = self.fluid.s + + self.fluid.TX = state.T + dT, 0 + p2 = self.fluid.P + + self.fluid.TX = state.T, 1 + vg = 1.0 / self.fluid.density + hg = self.fluid.h + sg = self.fluid.s + + # Clausius-Clapeyron Relation + msg = 'At state: T=%s, rho=%s' % (state.T, state.rho) + self.assertNear((p2-p1)/dT, (hg-hf)/(state.T * (vg-vf)), + self.tol.dPdT, msg=msg) + + # True for a change in state at constant pressure and temperature + self.assertNear(hg-hf, state.T * (sg-sf), self.tol.hTs, msg=msg) + + def test_pressure(self): + for state in self.states: + self.fluid.TD = state.T, state.rho + # dP/drho is high for liquids, so relax tolerances + tol = 50 *self.tol.p if state.phase == 'liquid' else self.tol.p + tol *= state.tolMod + msg = 'At state: T=%s, rho=%s' % (state.T, state.rho) + self.assertNear(self.fluid.P, state.p, tol, msg=msg) + + def test_internal_energy(self): + for state in self.states: + self.fluid.TD = state.T, state.rho + msg = 'At state: T=%s, rho=%s' % (state.T, state.rho) + self.assertNear(self.fluid.u - self.u0, + state.u - self.refState.u, + self.tol.u * state.tolMod, msg=msg) + + def test_entropy(self): + for state in self.states: + self.fluid.TD = state.T, state.rho + msg = 'At state: T=%s, rho=%s' % (state.T, state.rho) + self.assertNear(self.fluid.s - self.s0, + state.s - self.refState.s, + self.tol.s * state.tolMod, msg=msg) + +# Reference values for HFC134a taken from NIST Chemistry WebBook, which +# implements the same EOS from Tillner-Roth and Baehr as Cantera, so close +# agreement is expected. + +class HFC134a(PureFluidTestCases, utilities.CanteraTest): + states = [ + StateData('liquid', 175.0, 0.1, rho=1577.6239, u=77.534586, s=0.44788182), + StateData('liquid', 210.0, 0.1, rho=1483.2128, u=119.48566, s=0.66633877), + StateData('vapor', 250.0, 0.1, rho=5.1144317, u=365.59424, s=1.7577491), + StateData('vapor', 370.0, 0.1, rho=3.3472612, u=459.82664, s=2.0970769), + StateData('liquid', 290.0, 10, rho=1278.4700, u=216.99119, s=1.0613409), + StateData('super', 410.0, 10, rho=736.54666, u=399.02258, s=1.5972395), + StateData('super', 450.0, 40, rho=999.34087, u=411.92422, s=1.6108568)] + + def __init__(self, *args, **kwargs): + refState = StateData('critical', 374.21, 4.05928, + rho=511.900, u=381.70937, s=1.5620991) + PureFluidTestCases.__init__(self, 'hfc134a', refState) + utilities.CanteraTest.__init__(self, *args, **kwargs) + +# Reference values for the following substances are taken from the tables in +# W.C. Reynolds, "Thermodynamic Properties in SI", which is the source of +# Cantera's equations of state for these substances. Agreement is limited by +# the precision of the results printed in the book (typically 4 significant +# figures). + +# Property comparisons for saturated states are further limited by the use of +# different methods for satisfying the phase equilibrium condition g_l = g_v. +# Cantera uses the actual equation of state, while the tabulated values given +# by Reynolds are based on the given P_sat(T_sat) relations. + +class CarbonDioxide(PureFluidTestCases, utilities.CanteraTest): + states = [ + StateData('liquid', 230.0, 2.0, rho=1132.4, h=28.25, s=0.1208), + StateData('liquid', 270.0, 10.0, rho=989.97, h=110.59, s=0.4208), + StateData('vapor', 250.0, 1.788, v=0.02140, h=358.59, s=1.4500, relax=True), #sat + StateData('vapor', 300.0, 2.0, v=0.02535, h=409.41, s=1.6174), + StateData('super', 500.0, 1.0, v=0.09376, h=613.22, s=2.2649), + StateData('super', 600.0, 20.0, v=0.00554, h=681.94, s=1.8366)] + + def __init__(self, *args, **kwargs): + refState = StateData('critical', 304.21, 7.3834, + rho=464.0, h=257.31, s=0.9312) + tols = Tolerances(2e-3, 2e-3, 2e-3) + PureFluidTestCases.__init__(self, 'carbondioxide', refState, tols) + utilities.CanteraTest.__init__(self, *args, **kwargs) + + +class Heptane(PureFluidTestCases, utilities.CanteraTest): + states = [ + StateData('liquid', 300.0, 0.006637, v=0.001476, h=0.0, s=0.0, relax=True), #sat + StateData('liquid', 400.0, 0.2175, v=0.001712, h=248.01, s=0.709, relax=True), #sat + StateData('vapor', 490.0, 1.282, v=0.02222, h=715.64, s=1.7137, relax=True), #sat + StateData('vapor', 480.0, 0.70, v=0.04820, h=713.04, s=1.7477), + StateData('super', 600.0, 2.0, v=0.01992, h=1014.87, s=2.2356), + StateData('super', 680.0, 0.2, v=0.2790, h=1289.29, s=2.8450)] + + def __init__(self, *args, **kwargs): + refState = StateData('critical', 537.68, 2.6199, + rho=197.60, h=747.84, s=1.7456) + tols = Tolerances(2e-3, 2e-3, 2e-3) + PureFluidTestCases.__init__(self, 'heptane', refState, tols) + utilities.CanteraTest.__init__(self, *args, **kwargs) + + +# para-hydrogen +class Hydrogen(PureFluidTestCases, utilities.CanteraTest): + states = [ + StateData('liquid', 18.0, 0.04807, v=0.013660, h=30.1, s=1.856, relax=True), #sat + StateData('liquid', 26.0, 0.4029, v=0.015911, h=121.2, s=5.740, relax=True), #sat + StateData('vapor', 30.0, 0.8214, v=0.09207, h=487.4, s=17.859, relax=True), #sat + StateData('super', 100.0, 0.20, v=2.061, h=1398.3, s=39.869), + StateData('super', 200.0, 20.0, v=0.04795, h=3015.9, s=31.274), + StateData('super', 300.0, 0.50, v=2.482, h=4511.6, s=53.143), + StateData('super', 600.0, 1.00, v=2.483, h=8888.4, s=60.398), + StateData('super', 800.0, 4.0, v=0.8329, h=11840.0, s=58.890)] + + def __init__(self, *args, **kwargs): + refState = StateData('critical', 32.938, 1.2838, + rho=31.36, h=346.5, s=12.536) + tols = Tolerances(2e-3, 2e-3, 2e-3, 2e-4) + PureFluidTestCases.__init__(self, 'hydrogen', refState, tols) + utilities.CanteraTest.__init__(self, *args, **kwargs) + + +class Methane(PureFluidTestCases, utilities.CanteraTest): + states = [ + StateData('liquid', 100.0, 0.50, rho=439.39, h=31.65, s=0.3206), + StateData('liquid', 140.0, 2.0, rho=379.51, h=175.48, s=1.4963), + StateData('vapor', 150.0, 0.20, v=0.3772, h=660.72, s=5.5435), + StateData('vapor', 160.0, 1.594, v=0.03932, h=627.96, s=4.3648, relax=True), #sat + StateData('vapor', 175.0, 1.0, v=0.08157, h=692.55, s=4.9558), + StateData('super', 200.0, 0.2, v=0.5117, h=767.37, s=6.1574), + StateData('super', 300.0, 0.5, v=0.3083, h=980.87, s=6.5513)] + + def __init__(self, *args, **kwargs): + refState = StateData('critical', 190.555, 4.5988, + rho=160.43, h=490.61, s=3.2853) + tols = Tolerances(2e-3, 2e-3, 2e-3) + PureFluidTestCases.__init__(self, 'methane', refState, tols) + utilities.CanteraTest.__init__(self, *args, **kwargs) + + +class Nitrogen(PureFluidTestCases, utilities.CanteraTest): + states = [ + StateData('liquid', 80.0, 0.1370, v=0.001256, h=33.50, s=0.4668, relax=True), #sat + StateData('vapor', 110.0, 1.467, v=0.01602, h=236.28, s=2.3896, relax=True), #sat + StateData('super', 200.0, 0.5, v=0.1174, h=355.05, s=3.5019), + StateData('super', 300.0, 10.0, v=0.00895, h=441.78, s=2.9797), + StateData('super', 500.0, 5.0, v=0.03031, h=668.48, s=3.7722), + StateData('super', 600.0, 100.0, v=0.00276, h=827.54, s=3.0208)] + + def __init__(self, *args, **kwargs): + refState = StateData('critical', 126.200, 3.400, + rho=314.03, h=180.78, s=1.7903) + tols = Tolerances(2e-3, 2e-3, 2e-3) + PureFluidTestCases.__init__(self, 'nitrogen', refState, tols) + utilities.CanteraTest.__init__(self, *args, **kwargs) + + +class Oxygen(PureFluidTestCases, utilities.CanteraTest): + states = [ + StateData('liquid', 80.0, 0.03009, v=0.000840, h=42.56, s=0.6405, relax=True), #sat + StateData('liquid', 125.0, 1.351, v=0.001064, h=123.24, s=1.4236, relax=True), #sat + StateData('vapor', 145.0, 3.448, v=0.006458, h=276.45, s=2.4852, relax=True), #sat + StateData('super', 200.0, 0.050, v=1.038, h=374.65, s=4.1275), + StateData('super', 300.0, 1.0, v=0.07749, h=463.76, s=3.7135), + StateData('super', 600.0, 0.20, v=0.7798, h=753.38, s=4.7982), + StateData('super', 800.0, 5.0, v=0.04204, h=961.00, s=4.2571) + ] + + def __init__(self, *args, **kwargs): + refState = StateData('critical', 154.581, 5.0429, + rho=436.15, h=226.53, s=2.1080) + tols = Tolerances(2e-3, 2e-3, 2e-3) + PureFluidTestCases.__init__(self, 'oxygen', refState, tols) + utilities.CanteraTest.__init__(self, *args, **kwargs) + + +class Water(PureFluidTestCases, utilities.CanteraTest): + states = [ + StateData('liquid', 295.0, 0.002620, v=0.0010025, h=90.7, s=0.3193, relax=True), + StateData('vapor', 315.0, 0.008143, v=17.80, h=2577.1, s=8.2216, relax=True), + StateData('liquid', 440.0, 0.7332, v=0.001110, h=705.0, s=2.0096, relax=True), + StateData('vapor', 510.0, 3.163, v=0.06323, h=2803.6, s=6.1652, relax=True), + StateData('vapor', 400.0, 0.004, v=46.13, h=2738.8, s=9.0035), + StateData('vapor', 500.0, 1.0, v=0.2206, h=2890.2, s=6.8223), + StateData('super', 800.0, 0.01, v=36.92, h=3546.0, s=9.9699), + StateData('super', 900.0, 0.70, v=0.5917, h=3759.4, s=8.2621), + StateData('super', 1000.0, 30.0, v=0.01421, h=3821.6, s=6.6373), + StateData('liquid', 500.0, 3.0, rho=832.04, h=975.68, s=2.58049) + ] + + def __init__(self, *args, **kwargs): + refState = StateData('critical', 647.286, 22.089, + rho=317.0, h=2098.8, s=4.4289) + tols = Tolerances(2e-3, 2e-3, 2e-3) + PureFluidTestCases.__init__(self, 'water', refState, tols) + utilities.CanteraTest.__init__(self, *args, **kwargs) + + +class PureFluidConvergence(utilities.CanteraTest): + def setUp(self): + self.fluid = ct.Water() + + def test_TP(self): + # Focus on the region near the critical point + TT = [273.161, 300.0, 350.0, 400.0, 500.0, + 600.0, 640.0, 645.0, 646.0, 647.0, + 647.1, 647.2, 647.22, 647.23, 647.25, + 647.26, 647.27, 647.28, 647.282, 647.284, + 647.285, 647.286, 647.287, 650.0, 800.0] + PP = [1234.0, 101325.0, 5e5, 22.0e6, 22.08e6, 22.09e6, 10001000.0] + + errors = '' + nErrors = 0 + for T,P in itertools.product(TT,PP): + try: + self.fluid.TP = T, P + self.assertNear(self.fluid.T, T, 1e-6) + self.assertNear(self.fluid.P, P, 1e-6) + except Exception as e: + errors += 'Error at T=%r, P=%r:\n%s\n\n' % (T,P,e) + nErrors += 1 + if errors: + errors += 'Total error count:%s\n' % nErrors + raise AssertionError(errors) + + def test_UV(self): + u0 = -1.58581e7 + UU = np.array([0, 100, 200, 500, 1000, 1500, 2000]) * 1000 + u0 + VV = [0.001, 0.002, 0.005, 0.010, 0.10, 0.5, 1.0, 1.5, 2.0] + errors = '' + nErrors = 0 + for u,v in itertools.product(UU,VV): + try: + self.fluid.UV = u, v + self.assertNear(self.fluid.u, u, 1e-6) + self.assertNear(self.fluid.v, v, 1e-6) + except Exception as e: + errors += 'Error at u=%r, v=%r:\n%s\n\n' % (u,v,e) + nErrors += 1 + if errors: + errors += 'Total error count:%s\n' % nErrors + raise AssertionError(errors) + + def test_HP(self): + h0 = -1.58581e7 + HH = np.array([0, 100, 200, 500, 1000, 1500, 2000]) * 1000 + h0 + PP = [1234.0, 101325.0, 5e5, 22.0e6, 22.08e6, 22.09e6, 10001000.0] + errors = '' + nErrors = 0 + for h,P in itertools.product(HH,PP): + try: + self.fluid.HP = h, P + self.assertNear(self.fluid.h, h, 1e-6) + self.assertNear(self.fluid.P, P, 1e-6) + except Exception as e: + errors += 'Error at h=%r, P=%r:\n%s\n\n' % (h,P,e) + nErrors += 1 + if errors: + errors += 'Total error count:%s\n' % nErrors + raise AssertionError(errors) diff --git a/test/python/runTests.py b/test/python/runTests.py index a1d352b5f..b26743154 100644 --- a/test/python/runTests.py +++ b/test/python/runTests.py @@ -21,8 +21,7 @@ if __name__ == '__main__': loader = unittest.TestLoader() runner = unittest.TextTestRunner(verbosity=2) - suite = loader.loadTestsFromName('testPureFluid') - suite.addTests(loader.loadTestsFromName('testEquilibrium')) + suite = loader.loadTestsFromName('testEquilibrium') suite.addTests(loader.loadTestsFromName('testReactors')) suite.addTests(loader.loadTestsFromName('testConvert')) diff --git a/test/python/testPureFluid.py b/test/python/testPureFluid.py deleted file mode 100644 index 39825571c..000000000 --- a/test/python/testPureFluid.py +++ /dev/null @@ -1,361 +0,0 @@ -from __future__ import division - -import itertools -import utilities -import numpy as np -import Cantera as ct -import Cantera.liquidvapor as lv - -# To minimize errors when transcribing tabulated data, the input units here are: -# T: K, P: MPa, rho: kg/m3, v: m3/kg, (u,h): kJ/kg, s: kJ/kg-K -# Which are then converted to SI -class StateData(object): - def __init__(self, phase, T, p, rho=None, v=None, u=None, h=None, s=None, relax=False): - self.phase = phase - self.T = T - self.p = p * 1e6 - self.rho = rho if rho else 1.0/v - self.u = 1e3 * u if u is not None else 1e3 * h - self.p/self.rho - self.s = 1e3 * s - self.tolMod = 10.0 if relax else 1.0 - - -class Tolerances(object): - def __init__(self, p=None, u=None, s=None, - dUdS=None, dAdV=None, dPdT=None, hTs=None): - self.p = p or 2e-5 - self.u = u or 2e-6 - self.s = s or 2e-6 - self.dUdS = dUdS or 2e-6 - self.dAdV = dAdV or 2e-6 - self.dPdT = dPdT or 2e-4 - self.hTs = hTs or 2e-4 - - -class PureFluidTestCases(object): - fluids = {} - - def __init__(self, name, refState, tolerances=Tolerances()): - if name not in self.fluids: - self.fluids[name] = lv.PureFluid('liquidvapor.cti', name) - - self.fluid = self.fluids[name] - - self.fluid.set(T=refState.T, Rho=refState.rho) - self.refState = refState - self.u0 = self.fluid.intEnergy_mass() - self.s0 = self.fluid.entropy_mass() - self.tol = tolerances - - def a(self, T, rho): - """ Helmholtz free energy """ - self.fluid.set(T=T, Rho=rho) - return self.fluid.intEnergy_mass() - T * self.fluid.entropy_mass() - - def test_ConsistencyTemperature(self): - for state in self.states: - dT = 2e-5 * state.T - self.fluid.set(T=state.T-dT, Rho=state.rho) - s1 = self.fluid.entropy_mass() - u1 = self.fluid.intEnergy_mass() - self.fluid.set(T=state.T+dT, Rho=state.rho) - s2 = self.fluid.entropy_mass() - u2 = self.fluid.intEnergy_mass() - - # At constant volume, dU = T dS - msg = 'At state: T=%s, rho=%s' % (state.T, state.rho) - self.assertNear((u2-u1)/(s2-s1), state.T, self.tol.dUdS, msg=msg) - - def test_ConsistencyVolume(self): - for state in self.states: - self.fluid.set(T=state.T, Rho=state.rho) - p = self.fluid.pressure() - V = 1 / state.rho - dV = 5e-6 * V - - a1 = self.a(state.T, 1/(V-0.5*dV)) - a2 = self.a(state.T, 1/(V+0.5*dV)) - - # dP/drho is high for liquids, so relax tolerances - tol = 100 *self.tol.dAdV if state.phase == 'liquid' else self.tol.dAdV - - # At constant temperature, dA = - p dV - msg = 'At state: T=%s, rho=%s' % (state.T, state.rho) - self.assertNear(-(a2-a1)/dV, p, tol, msg=msg) - - def test_saturation(self): - for state in self.states: - if state.phase == 'super': - continue - - dT = 1e-6 * state.T - self.fluid.set(T=state.T, Vapor=0) - p1 = self.fluid.pressure() - vf = 1.0 / self.fluid.density() - hf = self.fluid.enthalpy_mass() - sf = self.fluid.entropy_mass() - - self.fluid.set(T=state.T + dT, Vapor=0) - p2 = self.fluid.pressure() - - self.fluid.set(T=state.T, Vapor=1) - vg = 1.0 / self.fluid.density() - hg = self.fluid.enthalpy_mass() - sg = self.fluid.entropy_mass() - - # Clausius-Clapeyron Relation - msg = 'At state: T=%s, rho=%s' % (state.T, state.rho) - self.assertNear((p2-p1)/dT, (hg-hf)/(state.T * (vg-vf)), - self.tol.dPdT, msg=msg) - - # True for a change in state at constant pressure and temperature - self.assertNear(hg-hf, state.T * (sg-sf), self.tol.hTs, msg=msg) - - def test_pressure(self): - for state in self.states: - self.fluid.set(T=state.T, Rho=state.rho) - # dP/drho is high for liquids, so relax tolerances - tol = 50 *self.tol.p if state.phase == 'liquid' else self.tol.p - tol *= state.tolMod - msg = 'At state: T=%s, rho=%s' % (state.T, state.rho) - self.assertNear(self.fluid.pressure(), state.p, tol, msg=msg) - - def test_internalEnergy(self): - for state in self.states: - self.fluid.set(T=state.T, Rho=state.rho) - msg = 'At state: T=%s, rho=%s' % (state.T, state.rho) - self.assertNear(self.fluid.intEnergy_mass()-self.u0, - state.u - self.refState.u, - self.tol.u * state.tolMod, msg=msg) - - def test_entropy(self): - for state in self.states: - self.fluid.set(T=state.T, Rho=state.rho) - msg = 'At state: T=%s, rho=%s' % (state.T, state.rho) - self.assertNear(self.fluid.entropy_mass()-self.s0, - state.s - self.refState.s, - self.tol.s * state.tolMod, msg=msg) - -# Reference values for HFC134a taken from NIST Chemistry WebBook, which -# implements the same EOS from Tillner-Roth and Baehr as Cantera, so close -# agreement is expected. - -class HFC134a(PureFluidTestCases, utilities.CanteraTest): - states = [ - StateData('liquid', 175.0, 0.1, rho=1577.6239, u=77.534586, s=0.44788182), - StateData('liquid', 210.0, 0.1, rho=1483.2128, u=119.48566, s=0.66633877), - StateData('vapor', 250.0, 0.1, rho=5.1144317, u=365.59424, s=1.7577491), - StateData('vapor', 370.0, 0.1, rho=3.3472612, u=459.82664, s=2.0970769), - StateData('liquid', 290.0, 10, rho=1278.4700, u=216.99119, s=1.0613409), - StateData('super', 410.0, 10, rho=736.54666, u=399.02258, s=1.5972395), - StateData('super', 450.0, 40, rho=999.34087, u=411.92422, s=1.6108568)] - - def __init__(self, *args, **kwargs): - refState = StateData('critical', 374.21, 4.05928, - rho=511.900, u=381.70937, s=1.5620991) - PureFluidTestCases.__init__(self, 'hfc134a', refState) - utilities.CanteraTest.__init__(self, *args, **kwargs) - -# Reference values for the following substances are taken from the tables in -# W.C. Reynolds, "Thermodynamic Properties in SI", which is the source of -# Cantera's equations of state for these substances. Agreement is limited by -# the precision of the results printed in the book (typically 4 significant -# figures). - -# Property comparisons for saturated states are further limited by the use of -# different methods for satisfying the phase equilibrium condition g_l = g_v. -# Cantera uses the actual equation of state, while the tabulated values given -# by Reynolds are based on the given P_sat(T_sat) relations. - -class CarbonDioxide(PureFluidTestCases, utilities.CanteraTest): - states = [ - StateData('liquid', 230.0, 2.0, rho=1132.4, h=28.25, s=0.1208), - StateData('liquid', 270.0, 10.0, rho=989.97, h=110.59, s=0.4208), - StateData('vapor', 250.0, 1.788, v=0.02140, h=358.59, s=1.4500, relax=True), #sat - StateData('vapor', 300.0, 2.0, v=0.02535, h=409.41, s=1.6174), - StateData('super', 500.0, 1.0, v=0.09376, h=613.22, s=2.2649), - StateData('super', 600.0, 20.0, v=0.00554, h=681.94, s=1.8366)] - - def __init__(self, *args, **kwargs): - refState = StateData('critical', 304.21, 7.3834, - rho=464.0, h=257.31, s=0.9312) - tols = Tolerances(2e-3, 2e-3, 2e-3) - PureFluidTestCases.__init__(self, 'carbondioxide', refState, tols) - utilities.CanteraTest.__init__(self, *args, **kwargs) - - -class Heptane(PureFluidTestCases, utilities.CanteraTest): - states = [ - StateData('liquid', 300.0, 0.006637, v=0.001476, h=0.0, s=0.0, relax=True), #sat - StateData('liquid', 400.0, 0.2175, v=0.001712, h=248.01, s=0.709, relax=True), #sat - StateData('vapor', 490.0, 1.282, v=0.02222, h=715.64, s=1.7137, relax=True), #sat - StateData('vapor', 480.0, 0.70, v=0.04820, h=713.04, s=1.7477), - StateData('super', 600.0, 2.0, v=0.01992, h=1014.87, s=2.2356), - StateData('super', 680.0, 0.2, v=0.2790, h=1289.29, s=2.8450)] - - def __init__(self, *args, **kwargs): - refState = StateData('critical', 537.68, 2.6199, - rho=197.60, h=747.84, s=1.7456) - tols = Tolerances(2e-3, 2e-3, 2e-3) - PureFluidTestCases.__init__(self, 'heptane', refState, tols) - utilities.CanteraTest.__init__(self, *args, **kwargs) - - -# para-hydrogen -class Hydrogen(PureFluidTestCases, utilities.CanteraTest): - states = [ - StateData('liquid', 18.0, 0.04807, v=0.013660, h=30.1, s=1.856, relax=True), #sat - StateData('liquid', 26.0, 0.4029, v=0.015911, h=121.2, s=5.740, relax=True), #sat - StateData('vapor', 30.0, 0.8214, v=0.09207, h=487.4, s=17.859, relax=True), #sat - StateData('super', 100.0, 0.20, v=2.061, h=1398.3, s=39.869), - StateData('super', 200.0, 20.0, v=0.04795, h=3015.9, s=31.274), - StateData('super', 300.0, 0.50, v=2.482, h=4511.6, s=53.143), - StateData('super', 600.0, 1.00, v=2.483, h=8888.4, s=60.398), - StateData('super', 800.0, 4.0, v=0.8329, h=11840.0, s=58.890)] - - def __init__(self, *args, **kwargs): - refState = StateData('critical', 32.938, 1.2838, - rho=31.36, h=346.5, s=12.536) - tols = Tolerances(2e-3, 2e-3, 2e-3, 2e-4) - PureFluidTestCases.__init__(self, 'hydrogen', refState, tols) - utilities.CanteraTest.__init__(self, *args, **kwargs) - - -class Methane(PureFluidTestCases, utilities.CanteraTest): - states = [ - StateData('liquid', 100.0, 0.50, rho=439.39, h=31.65, s=0.3206), - StateData('liquid', 140.0, 2.0, rho=379.51, h=175.48, s=1.4963), - StateData('vapor', 150.0, 0.20, v=0.3772, h=660.72, s=5.5435), - StateData('vapor', 160.0, 1.594, v=0.03932, h=627.96, s=4.3648, relax=True), #sat - StateData('vapor', 175.0, 1.0, v=0.08157, h=692.55, s=4.9558), - StateData('super', 200.0, 0.2, v=0.5117, h=767.37, s=6.1574), - StateData('super', 300.0, 0.5, v=0.3083, h=980.87, s=6.5513)] - - def __init__(self, *args, **kwargs): - refState = StateData('critical', 190.555, 4.5988, - rho=160.43, h=490.61, s=3.2853) - tols = Tolerances(2e-3, 2e-3, 2e-3) - PureFluidTestCases.__init__(self, 'methane', refState, tols) - utilities.CanteraTest.__init__(self, *args, **kwargs) - - -class Nitrogen(PureFluidTestCases, utilities.CanteraTest): - states = [ - StateData('liquid', 80.0, 0.1370, v=0.001256, h=33.50, s=0.4668, relax=True), #sat - StateData('vapor', 110.0, 1.467, v=0.01602, h=236.28, s=2.3896, relax=True), #sat - StateData('super', 200.0, 0.5, v=0.1174, h=355.05, s=3.5019), - StateData('super', 300.0, 10.0, v=0.00895, h=441.78, s=2.9797), - StateData('super', 500.0, 5.0, v=0.03031, h=668.48, s=3.7722), - StateData('super', 600.0, 100.0, v=0.00276, h=827.54, s=3.0208)] - - def __init__(self, *args, **kwargs): - refState = StateData('critical', 126.200, 3.400, - rho=314.03, h=180.78, s=1.7903) - tols = Tolerances(2e-3, 2e-3, 2e-3) - PureFluidTestCases.__init__(self, 'nitrogen', refState, tols) - utilities.CanteraTest.__init__(self, *args, **kwargs) - - -class Oxygen(PureFluidTestCases, utilities.CanteraTest): - states = [ - StateData('liquid', 80.0, 0.03009, v=0.000840, h=42.56, s=0.6405, relax=True), #sat - StateData('liquid', 125.0, 1.351, v=0.001064, h=123.24, s=1.4236, relax=True), #sat - StateData('vapor', 145.0, 3.448, v=0.006458, h=276.45, s=2.4852, relax=True), #sat - StateData('super', 200.0, 0.050, v=1.038, h=374.65, s=4.1275), - StateData('super', 300.0, 1.0, v=0.07749, h=463.76, s=3.7135), - StateData('super', 600.0, 0.20, v=0.7798, h=753.38, s=4.7982), - StateData('super', 800.0, 5.0, v=0.04204, h=961.00, s=4.2571) - ] - - def __init__(self, *args, **kwargs): - refState = StateData('critical', 154.581, 5.0429, - rho=436.15, h=226.53, s=2.1080) - tols = Tolerances(2e-3, 2e-3, 2e-3) - PureFluidTestCases.__init__(self, 'oxygen', refState, tols) - utilities.CanteraTest.__init__(self, *args, **kwargs) - - -class Water(PureFluidTestCases, utilities.CanteraTest): - states = [ - StateData('liquid', 295.0, 0.002620, v=0.0010025, h=90.7, s=0.3193, relax=True), - StateData('vapor', 315.0, 0.008143, v=17.80, h=2577.1, s=8.2216, relax=True), - StateData('liquid', 440.0, 0.7332, v=0.001110, h=705.0, s=2.0096, relax=True), - StateData('vapor', 510.0, 3.163, v=0.06323, h=2803.6, s=6.1652, relax=True), - StateData('vapor', 400.0, 0.004, v=46.13, h=2738.8, s=9.0035), - StateData('vapor', 500.0, 1.0, v=0.2206, h=2890.2, s=6.8223), - StateData('super', 800.0, 0.01, v=36.92, h=3546.0, s=9.9699), - StateData('super', 900.0, 0.70, v=0.5917, h=3759.4, s=8.2621), - StateData('super', 1000.0, 30.0, v=0.01421, h=3821.6, s=6.6373), - StateData('liquid', 500.0, 3.0, rho=832.04, h=975.68, s=2.58049) - ] - - def __init__(self, *args, **kwargs): - refState = StateData('critical', 647.286, 22.089, - rho=317.0, h=2098.8, s=4.4289) - tols = Tolerances(2e-3, 2e-3, 2e-3) - PureFluidTestCases.__init__(self, 'water', refState, tols) - utilities.CanteraTest.__init__(self, *args, **kwargs) - - -class Convergence(utilities.CanteraTest): - def setUp(self): - self.fluid = lv.Water() - - def test_TP(self): - # Focus on the region near the critical point - TT = [273.161, 300.0, 350.0, 400.0, 500.0, - 600.0, 640.0, 645.0, 646.0, 647.0, - 647.1, 647.2, 647.22, 647.23, 647.25, - 647.26, 647.27, 647.28, 647.282, 647.284, - 647.285, 647.286, 647.287, 650.0, 800.0] - PP = [1234.0, 101325.0, 5e5, 22.0e6, 22.08e6, 22.09e6, 10001000.0] - - errors = '' - nErrors = 0 - for T,P in itertools.product(TT,PP): - try: - self.fluid.set(T=T, P=P) - self.assertNear(self.fluid.temperature(), T, 1e-6) - self.assertNear(self.fluid.pressure(), P, 1e-6) - except Exception as e: - errors += 'Error at T=%r, P=%r:\n%s\n\n' % (T,P,e) - nErrors += 1 - if errors: - errors += 'Total error count:%s\n' % nErrors - raise AssertionError(errors) - - def test_UV(self): - u0 = -1.58581e7 - UU = np.array([0, 100, 200, 500, 1000, 1500, 2000]) * 1000 + u0 - VV = [0.001, 0.002, 0.005, 0.010, 0.10, 0.5, 1.0, 1.5, 2.0] - errors = '' - nErrors = 0 - for u,v in itertools.product(UU,VV): - try: - self.fluid.set(U=u, V=v) - self.assertNear(self.fluid.intEnergy_mass(), u, 1e-6) - self.assertNear(self.fluid.volume_mass(), v, 1e-6) - except Exception as e: - errors += 'Error at u=%r, v=%r:\n%s\n\n' % (u,v,e) - nErrors += 1 - if errors: - errors += 'Total error count:%s\n' % nErrors - raise AssertionError(errors) - - def test_HP(self): - h0 = -1.58581e7 - HH = np.array([0, 100, 200, 500, 1000, 1500, 2000]) * 1000 + h0 - PP = [1234.0, 101325.0, 5e5, 22.0e6, 22.08e6, 22.09e6, 10001000.0] - errors = '' - nErrors = 0 - for h,P in itertools.product(HH,PP): - try: - self.fluid.set(H=h, P=P) - self.assertNear(self.fluid.enthalpy_mass(), h, 1e-6) - self.assertNear(self.fluid.pressure(), P, 1e-6) - except Exception as e: - errors += 'Error at h=%r, P=%r:\n%s\n\n' % (h,P,e) - nErrors += 1 - if errors: - errors += 'Total error count:%s\n' % nErrors - raise AssertionError(errors)