From dc4d231184ef5e259fc272878515ea86884fd935 Mon Sep 17 00:00:00 2001 From: Doug A Date: Thu, 30 Jan 2025 16:21:57 -0500 Subject: [PATCH 1/3] fix bugs in smooth_vle initialization --- .../phase_equil/smooth_VLE_2.py | 6 +- .../phase_equil/tests/test_smooth_VLE_2.py | 84 ++++++++++++++++++- 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/idaes/models/properties/modular_properties/phase_equil/smooth_VLE_2.py b/idaes/models/properties/modular_properties/phase_equil/smooth_VLE_2.py index 679e326d90..0671ed029a 100644 --- a/idaes/models/properties/modular_properties/phase_equil/smooth_VLE_2.py +++ b/idaes/models/properties/modular_properties/phase_equil/smooth_VLE_2.py @@ -243,11 +243,11 @@ def calculate_teq(blk, pp): vapor_phase, raoult_comps, henry_comps, - _, + l_only_comps, v_only_comps, ) = identify_VL_component_list(blk, pp) - if v_only_comps is None: + if len(v_only_comps) == 0: if blk.is_property_constructed("temperature_bubble"): Tbub = value(blk.temperature_bubble[pp]) else: @@ -258,7 +258,7 @@ def calculate_teq(blk, pp): else: t1 = value(blk.temperature) - if v_only_comps is None: + if len(l_only_comps) == 0: if blk.is_property_constructed("temperature_dew"): Tdew = value(blk.temperature_bubble[pp]) else: diff --git a/idaes/models/properties/modular_properties/phase_equil/tests/test_smooth_VLE_2.py b/idaes/models/properties/modular_properties/phase_equil/tests/test_smooth_VLE_2.py index 482c49fda8..a4682fb8e8 100644 --- a/idaes/models/properties/modular_properties/phase_equil/tests/test_smooth_VLE_2.py +++ b/idaes/models/properties/modular_properties/phase_equil/tests/test_smooth_VLE_2.py @@ -28,6 +28,9 @@ units as pyunits, ) +from idaes.core.base.phases import PhaseType +from idaes.core.util.exceptions import ConfigurationError + from idaes.models.properties.modular_properties.base.generic_property import ( GenericParameterBlock, ) @@ -41,7 +44,8 @@ from idaes.models.properties.modular_properties.eos.ideal import Ideal from idaes.models.properties.modular_properties.eos.ceos import Cubic, CubicType from idaes.models.properties.modular_properties.phase_equil.forms import fugacity -from idaes.core.util.exceptions import ConfigurationError + +from idaes.models.properties.modular_properties.pure.NIST import NIST @pytest.mark.unit @@ -339,3 +343,81 @@ def test_calculate_ceos_derivative_slacks(frame): assert value(gp["Vap"]) == pytest.approx(EPS_INIT, abs=1e-8) assert value(gn["Vap"]) == pytest.approx(EPS_INIT, abs=1e-8) + + +@pytest.fixture() +def H2O_H2_model(): + m = ConcreteModel() + + # Create a dummy parameter block + m.params = GenericParameterBlock( + components={ + "H2O": { + "parameter_data": { + "pressure_crit": (220.6e5, pyunits.Pa), + "temperature_crit": (647, pyunits.K), + "omega": 0.344, + "pressure_sat_comp_coeff": { # NIST <- Stull 1947 + "A": 4.6543, + "B": 1435.264, + "C": -64.848, + }, + }, + "pressure_sat_comp": NIST, + "phase_equilibrium_form": {("Vap", "Liq"): fugacity}, + }, + "H2": { + "valid_phase_types": [PhaseType.vaporPhase], + "parameter_data": { + "pressure_crit": (13e5, pyunits.Pa), + "temperature_crit": (33.2, pyunits.K), + "omega": -0.218, + }, + }, + }, + phases={ + "Liq": { + "equation_of_state": Cubic, + "equation_of_state_options": {"type": CubicType.PR}, + }, + "Vap": { + "equation_of_state": Cubic, + "equation_of_state_options": {"type": CubicType.PR}, + }, + }, + state_definition=FTPx, + pressure_ref=100000.0, + temperature_ref=300, + base_units={ + "time": pyunits.s, + "length": pyunits.m, + "mass": pyunits.kg, + "amount": pyunits.mol, + "temperature": pyunits.K, + }, + phases_in_equilibrium=[("Vap", "Liq")], + phase_equilibrium_state={("Vap", "Liq"): CubicComplementarityVLE}, + parameter_data={ + "PR_kappa": { + ("H2O", "H2O"): 0.000, + ("H2", "H2O"): 0.000, + ("H2O", "H2"): 0.000, + ("H2", "H2"): 0.000, + } + }, + ) + + # Create a dummy state block + m.props = m.params.state_block_class([1], parameters=m.params) + + return m + + +@pytest.mark.unit +def test_calculate_teq_permanent_gas(H2O_H2_model): + m = H2O_H2_model + m.props[1].pressure.set_value(1e5) + m.props[1].temperature.set_value(300) + CubicComplementarityVLE.calculate_teq(m.props[1], ("Vap", "Liq")) + assert not m.props[1].is_property_constructed("temperature_dew") + assert not m.props[1].is_property_constructed("temperature_bubble") From 9b9bdfa99d2391316afe8480cec1d0087e476aed Mon Sep 17 00:00:00 2001 From: Doug A Date: Fri, 31 Jan 2025 14:11:01 -0500 Subject: [PATCH 2/3] increase test coverage --- .../phase_equil/tests/test_smooth_VLE_2.py | 211 ++++++++++++------ 1 file changed, 146 insertions(+), 65 deletions(-) diff --git a/idaes/models/properties/modular_properties/phase_equil/tests/test_smooth_VLE_2.py b/idaes/models/properties/modular_properties/phase_equil/tests/test_smooth_VLE_2.py index a4682fb8e8..f1b047b6bc 100644 --- a/idaes/models/properties/modular_properties/phase_equil/tests/test_smooth_VLE_2.py +++ b/idaes/models/properties/modular_properties/phase_equil/tests/test_smooth_VLE_2.py @@ -345,79 +345,160 @@ def test_calculate_ceos_derivative_slacks(frame): assert value(gn["Vap"]) == pytest.approx(EPS_INIT, abs=1e-8) -@pytest.fixture() -def H2O_H2_model(): - m = ConcreteModel() - - # Create a dummy parameter block - m.params = GenericParameterBlock( - components={ - "H2O": { - "parameter_data": { - "pressure_crit": (220.6e5, pyunits.Pa), - "temperature_crit": (647, pyunits.K), - "omega": 0.344, - "pressure_sat_comp_coeff": { # NIST <- Stull 1947 - "A": 4.6543, - "B": 1435.264, - "C": -64.848, +class TestWithNonCondensable: + # TODO These tests could be fleshed out + @pytest.fixture() + def H2O_H2_model(self): + m = ConcreteModel() + + # Create a dummy parameter block + m.params = GenericParameterBlock( + components={ + "H2O": { + "parameter_data": { + "pressure_crit": (220.6e5, pyunits.Pa), + "temperature_crit": (647, pyunits.K), + "omega": 0.344, + "pressure_sat_comp_coeff": { # NIST <- Stull 1947 + "A": 4.6543, + "B": 1435.264, + "C": -64.848, + }, + }, + "pressure_sat_comp": NIST, + "phase_equilibrium_form": {("Vap", "Liq"): fugacity}, + }, + "H2": { + "valid_phase_types": [PhaseType.vaporPhase], + "parameter_data": { + "pressure_crit": (13e5, pyunits.Pa), + "temperature_crit": (33.2, pyunits.K), + "omega": -0.218, }, }, - "pressure_sat_comp": NIST, - "phase_equilibrium_form": {("Vap", "Liq"): fugacity}, }, - "H2": { - "valid_phase_types": [PhaseType.vaporPhase], - "parameter_data": { - "pressure_crit": (13e5, pyunits.Pa), - "temperature_crit": (33.2, pyunits.K), - "omega": -0.218, + phases={ + "Liq": { + "equation_of_state": Cubic, + "equation_of_state_options": {"type": CubicType.PR}, + }, + "Vap": { + "equation_of_state": Cubic, + "equation_of_state_options": {"type": CubicType.PR}, }, }, - }, - phases={ - "Liq": { - "equation_of_state": Cubic, - "equation_of_state_options": {"type": CubicType.PR}, + state_definition=FTPx, + pressure_ref=100000.0, + temperature_ref=300, + base_units={ + "time": pyunits.s, + "length": pyunits.m, + "mass": pyunits.kg, + "amount": pyunits.mol, + "temperature": pyunits.K, }, - "Vap": { - "equation_of_state": Cubic, - "equation_of_state_options": {"type": CubicType.PR}, + phases_in_equilibrium=[("Vap", "Liq")], + phase_equilibrium_state={("Vap", "Liq"): CubicComplementarityVLE}, + parameter_data={ + "PR_kappa": { + ("H2O", "H2O"): 0.000, + ("H2", "H2O"): 0.000, + ("H2O", "H2"): 0.000, + ("H2", "H2"): 0.000, + } }, - }, - state_definition=FTPx, - pressure_ref=100000.0, - temperature_ref=300, - base_units={ - "time": pyunits.s, - "length": pyunits.m, - "mass": pyunits.kg, - "amount": pyunits.mol, - "temperature": pyunits.K, - }, - phases_in_equilibrium=[("Vap", "Liq")], - phase_equilibrium_state={("Vap", "Liq"): CubicComplementarityVLE}, - parameter_data={ - "PR_kappa": { - ("H2O", "H2O"): 0.000, - ("H2", "H2O"): 0.000, - ("H2O", "H2"): 0.000, - ("H2", "H2"): 0.000, - } - }, - ) + ) - # Create a dummy state block - m.props = m.params.state_block_class([1], parameters=m.params) + # Create a dummy state block + m.props = m.params.state_block_class([1], parameters=m.params) - return m + return m + + @pytest.mark.unit + def test_calculate_teq_permanent_gas(self, H2O_H2_model): + m = H2O_H2_model + m.props[1].pressure.set_value(1e5) + m.props[1].temperature.set_value(300) + CubicComplementarityVLE.calculate_teq(m.props[1], ("Vap", "Liq")) + assert not m.props[1].is_property_constructed("temperature_dew") + assert not m.props[1].is_property_constructed("temperature_bubble") + + +class TestWithNonVolatile: + # TODO These tests could be fleshed out + @pytest.fixture() + def H2O_TEG_model(self): + m = ConcreteModel() + + # Create a dummy parameter block + m.params = GenericParameterBlock( + components={ + "H2O": { + "parameter_data": { + "pressure_crit": (220.6e5, pyunits.Pa), + "temperature_crit": (647, pyunits.K), + "omega": 0.344, + "pressure_sat_comp_coeff": { # NIST <- Stull 1947 + "A": 4.6543, + "B": 1435.264, + "C": -64.848, + }, + }, + "pressure_sat_comp": NIST, + "phase_equilibrium_form": {("Vap", "Liq"): fugacity}, + }, + "TEG": { # Triethylene Glycol + "valid_phase_types": [PhaseType.liquidPhase], + # Values from WolframAlpha + "parameter_data": { + "pressure_crit": (3.3e6, pyunits.Pa), + "temperature_crit": (797, pyunits.K), + "omega": 0.51, + }, + }, + }, + phases={ + "Liq": { + "equation_of_state": Cubic, + "equation_of_state_options": {"type": CubicType.PR}, + }, + "Vap": { + "equation_of_state": Cubic, + "equation_of_state_options": {"type": CubicType.PR}, + }, + }, + state_definition=FTPx, + pressure_ref=100000.0, + temperature_ref=300, + base_units={ + "time": pyunits.s, + "length": pyunits.m, + "mass": pyunits.kg, + "amount": pyunits.mol, + "temperature": pyunits.K, + }, + phases_in_equilibrium=[("Vap", "Liq")], + phase_equilibrium_state={("Vap", "Liq"): CubicComplementarityVLE}, + parameter_data={ + "PR_kappa": { + ("H2O", "H2O"): 0.000, + ("TEG", "H2O"): 0.000, + ("H2O", "TEG"): 0.000, + ("TEG", "TEG"): 0.000, + } + }, + ) + # Create a dummy state block + m.props = m.params.state_block_class([1], parameters=m.params) -@pytest.mark.unit -def test_calculate_teq_permanent_gas(H2O_H2_model): - m = H2O_H2_model - m.props[1].pressure.set_value(1e5) - m.props[1].temperature.set_value(300) - CubicComplementarityVLE.calculate_teq(m.props[1], ("Vap", "Liq")) - assert not m.props[1].is_property_constructed("temperature_dew") - assert not m.props[1].is_property_constructed("temperature_bubble") + return m + + @pytest.mark.unit + def test_calculate_teq_permanent_gas(self, H2O_TEG_model): + m = H2O_TEG_model + m.props[1].pressure.set_value(1e5) + m.props[1].temperature.set_value(300) + CubicComplementarityVLE.calculate_teq(m.props[1], ("Vap", "Liq")) + assert not m.props[1].is_property_constructed("temperature_dew") + assert not m.props[1].is_property_constructed("temperature_bubble") From aabc09838d634d0a9349ccb21d0ef591504a0051 Mon Sep 17 00:00:00 2001 From: Doug A Date: Thu, 6 Feb 2025 16:36:30 -0500 Subject: [PATCH 3/3] increase precision of IPOPT solve --- idaes/models/unit_models/tests/test_heat_exchanger_1D.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idaes/models/unit_models/tests/test_heat_exchanger_1D.py b/idaes/models/unit_models/tests/test_heat_exchanger_1D.py index 24b5679f56..67b9dc2020 100644 --- a/idaes/models/unit_models/tests/test_heat_exchanger_1D.py +++ b/idaes/models/unit_models/tests/test_heat_exchanger_1D.py @@ -85,7 +85,7 @@ # ----------------------------------------------------------------------------- # Get default solver for testing -solver = get_solver("ipopt_v2") +solver = get_solver("ipopt_v2", solver_options={"constr_viol_tol": 1e-6}) # -----------------------------------------------------------------------------