From ec049697775cdd23f78dc2f9a0257bf987c9aa76 Mon Sep 17 00:00:00 2001 From: Lingyan90 Date: Mon, 22 Dec 2025 15:15:00 -0500 Subject: [PATCH 1/5] revised the stream table content for ideal separation case activated the test for assert stream table contents under class TestBTIdealModular, to fix issue #1684 --- idaes/models/unit_models/flash.py | 68 +++++++------- idaes/models/unit_models/tests/test_flash.py | 93 ++++++++++---------- 2 files changed, 81 insertions(+), 80 deletions(-) diff --git a/idaes/models/unit_models/flash.py b/idaes/models/unit_models/flash.py index 4d9a6e3079..2542574154 100644 --- a/idaes/models/unit_models/flash.py +++ b/idaes/models/unit_models/flash.py @@ -360,41 +360,17 @@ def _get_stream_table_contents(self, time_point=0): stream_attributes = {} stream_attributes["Units"] = {} - sblocks = { - "Inlet": self.control_volume.properties_in, - } - if not self.config.ideal_separation: - # If not using ideal separation, we can get outlet state directly - # from the state blocks - sblocks["Vapor Outlet"] = self.split.Vap_state - sblocks["Liquid Outlet"] = self.split.Liq_state - - for n, v in sblocks.items(): - dvars = v[time_point].define_display_vars() - - stream_attributes[n] = {} - - for k in dvars: - for i in dvars[k].keys(): - stream_key = k if i is None else f"{k} {i}" - - quant = report_quantity(dvars[k][i]) - - stream_attributes[n][stream_key] = quant.m - stream_attributes["Units"][stream_key] = quant.u - if self.config.ideal_separation: - # If using ideal separation, get values from Ports and hope they map - # to names in Inlet - # TODO: Add a better way to map these if necessary - for n, v in { - "Vapor Outlet": "vap_outlet", - "Liquid Outlet": "liq_outlet", + # If using ideal separation, build the stream table from Ports so that + # all streams use the same naming covention (avoids mismatches with + # define_display_vars() across property packages). + for n, port_obj in { + "Inlet": self.inlet, + "Vapor Outlet": self.vap_outlet, + "Liquid Outlet": self.liq_outlet, }.items(): - port_obj = getattr(self, v) - - stream_attributes[n] = {} - + stream_attributes[n] ={} + for k in port_obj.vars: for i in port_obj.vars[k].keys(): if isinstance(i, float): @@ -402,12 +378,34 @@ def _get_stream_table_contents(self, time_point=0): stream_attributes[n][k] = quant.m stream_attributes["Units"][k] = quant.u else: - if len(i) == 2: + if len(i) ==2: kname = str(i[1]) else: kname = str(i[1:]) quant = report_quantity(port_obj.vars[k][time_point, i[1:]]) stream_attributes[n][k + " " + kname] = quant.m stream_attributes["Units"][k + " " + kname] = quant.u - + else: + # If not using idea separation, we can get outlet state directly + # from the state blocks + sblocks = { + "Inlet": self.control_volume.properties_in, + "Vapor Outlet": self.split.Vap_state, + "Liquid Outlet": self.split.Liq_state, + } + + for n, v in sblocks.items(): + dvars = v[time_point].define_display_vars() + + stream_attributes[n] = {} + + for k in dvars: + for i in dvars[k].keys(): + stream_key = k if i is None else f"{k} {i}" + + quant = report_quantity(dvars[k][i]) + + stream_attributes[n][stream_key] = quant.m + stream_attributes["Units"][stream_key] = quant.u + return DataFrame.from_dict(stream_attributes, orient="columns") diff --git a/idaes/models/unit_models/tests/test_flash.py b/idaes/models/unit_models/tests/test_flash.py index 290ddae7ec..14a16c2669 100644 --- a/idaes/models/unit_models/tests/test_flash.py +++ b/idaes/models/unit_models/tests/test_flash.py @@ -16,6 +16,7 @@ """ from copy import deepcopy import pytest +import pandas as pd from pyomo.environ import ( check_optimal_termination, @@ -255,7 +256,9 @@ def test_get_stream_table_contents(self, btx): "pressure": pytest.approx(101325.0, rel=1e-4), }, } - + stable = btx.fs.unit._get_stream_table_contents() + print("\n=== BTXIdeal STREAM TABLE ===") + print(stable) assert stable.to_dict() == expected @pytest.mark.solver @@ -344,7 +347,7 @@ def bt_modular(self): m.fs.unit.inlet.pressure.fix(101325) m.fs.unit.inlet.mole_frac_comp[0, "benzene"].fix(0.5) m.fs.unit.inlet.mole_frac_comp[0, "toluene"].fix(0.5) - + m.fs.unit.heat_duty.fix(0) m.fs.unit.deltaP.fix(0) @@ -406,49 +409,49 @@ def test_get_performance_contents(self, bt_modular): } } - # TODO the formatting for modular properties is broken (see #1684). - # This test can be fixed once that issue is fixed - # @pytest.mark.ui - # @pytest.mark.unit - # def test_get_stream_table_contents(self, bt_modular): - # stable = bt_modular.fs.unit._get_stream_table_contents() - - # expected = { - # "Units": { - # "flow_mol": getattr(pyunits.pint_registry, "mole/s"), - # "mole_frac_comp benzene": getattr( - # pyunits.pint_registry, "dimensionless" - # ), - # "mole_frac_comp toluene": getattr( - # pyunits.pint_registry, "dimensionless" - # ), - # "temperature": getattr(pyunits.pint_registry, "K"), - # "pressure": getattr(pyunits.pint_registry, "Pa"), - # }, - # "Inlet": { - # "flow_mol": pytest.approx(1.00, rel=1e-4), - # "mole_frac_comp benzene": pytest.approx(0.5, rel=1e-4), - # "mole_frac_comp toluene": pytest.approx(0.5, rel=1e-4), - # "temperature": pytest.approx(368, rel=1e-4), - # "pressure": pytest.approx(101325, rel=1e-4), - # }, - # "Vapor Outlet": { - # "flow_mol": pytest.approx(0.5, rel=1e-4), - # "mole_frac_comp benzene": pytest.approx(0.5, rel=1e-4), - # "mole_frac_comp toluene": pytest.approx(0.5, rel=1e-4), - # "temperature": pytest.approx(298.15, rel=1e-4), - # "pressure": pytest.approx(101325.0, rel=1e-4), - # }, - # "Liquid Outlet": { - # "flow_mol": pytest.approx(0.5, rel=1e-4), - # "mole_frac_comp benzene": pytest.approx(0.5, rel=1e-4), - # "mole_frac_comp toluene": pytest.approx(0.5, rel=1e-4), - # "temperature": pytest.approx(298.15, rel=1e-4), - # "pressure": pytest.approx(101325.0, rel=1e-4), - # }, - # } - - # assert stable.to_dict() == expected + @pytest.mark.ui + @pytest.mark.unit + def test_get_stream_table_contents(self, bt_modular): + stable = bt_modular.fs.unit._get_stream_table_contents() + + expected = { + "Units": { + "flow_mol": getattr(pyunits.pint_registry, "mole/s"), + "mole_frac_comp benzene": getattr( + pyunits.pint_registry, "dimensionless" + ), + "mole_frac_comp toluene": getattr( + pyunits.pint_registry, "dimensionless" + ), + "temperature": getattr(pyunits.pint_registry, "K"), + "pressure": getattr(pyunits.pint_registry, "Pa"), + }, + "Inlet": { + "flow_mol": pytest.approx(1.00, rel=1e-4), + "mole_frac_comp benzene": pytest.approx(0.5, rel=1e-4), + "mole_frac_comp toluene": pytest.approx(0.5, rel=1e-4), + "temperature": pytest.approx(368, rel=1e-4), + "pressure": pytest.approx(101325, rel=1e-4), + }, + "Vapor Outlet": { + "flow_mol": pytest.approx(50, rel=1e-4), + "mole_frac_comp benzene": pytest.approx(0.5, rel=1e-4), + "mole_frac_comp toluene": pytest.approx(0.5, rel=1e-4), + "temperature": pytest.approx(300.0, rel=1e-4), + "pressure": pytest.approx(100000.0, rel=1e-4), + }, + "Liquid Outlet": { + "flow_mol": pytest.approx(50, rel=1e-4), + "mole_frac_comp benzene": pytest.approx(0.5, rel=1e-4), + "mole_frac_comp toluene": pytest.approx(0.5, rel=1e-4), + "temperature": pytest.approx(300.0, rel=1e-4), + "pressure": pytest.approx(100000.0, rel=1e-4), + }, + } + stable = bt_modular.fs.unit._get_stream_table_contents() + print("\n=== BTIdealModular STREAM TABLE ===") + print(stable) + assert stable.to_dict() == expected @pytest.mark.solver @pytest.mark.skipif(solver is None, reason="Solver not available") From e540ce0f596391136934045cbc75600c89c5271d Mon Sep 17 00:00:00 2001 From: Lingyan90 Date: Mon, 22 Dec 2025 15:16:56 -0500 Subject: [PATCH 2/5] black --- idaes/models/unit_models/flash.py | 18 +++++++++--------- idaes/models/unit_models/tests/test_flash.py | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/idaes/models/unit_models/flash.py b/idaes/models/unit_models/flash.py index 2542574154..0861ed7d18 100644 --- a/idaes/models/unit_models/flash.py +++ b/idaes/models/unit_models/flash.py @@ -369,8 +369,8 @@ def _get_stream_table_contents(self, time_point=0): "Vapor Outlet": self.vap_outlet, "Liquid Outlet": self.liq_outlet, }.items(): - stream_attributes[n] ={} - + stream_attributes[n] = {} + for k in port_obj.vars: for i in port_obj.vars[k].keys(): if isinstance(i, float): @@ -378,7 +378,7 @@ def _get_stream_table_contents(self, time_point=0): stream_attributes[n][k] = quant.m stream_attributes["Units"][k] = quant.u else: - if len(i) ==2: + if len(i) == 2: kname = str(i[1]) else: kname = str(i[1:]) @@ -393,19 +393,19 @@ def _get_stream_table_contents(self, time_point=0): "Vapor Outlet": self.split.Vap_state, "Liquid Outlet": self.split.Liq_state, } - + for n, v in sblocks.items(): dvars = v[time_point].define_display_vars() - + stream_attributes[n] = {} - + for k in dvars: for i in dvars[k].keys(): stream_key = k if i is None else f"{k} {i}" - + quant = report_quantity(dvars[k][i]) - + stream_attributes[n][stream_key] = quant.m stream_attributes["Units"][stream_key] = quant.u - + return DataFrame.from_dict(stream_attributes, orient="columns") diff --git a/idaes/models/unit_models/tests/test_flash.py b/idaes/models/unit_models/tests/test_flash.py index 14a16c2669..31db87df66 100644 --- a/idaes/models/unit_models/tests/test_flash.py +++ b/idaes/models/unit_models/tests/test_flash.py @@ -347,7 +347,7 @@ def bt_modular(self): m.fs.unit.inlet.pressure.fix(101325) m.fs.unit.inlet.mole_frac_comp[0, "benzene"].fix(0.5) m.fs.unit.inlet.mole_frac_comp[0, "toluene"].fix(0.5) - + m.fs.unit.heat_duty.fix(0) m.fs.unit.deltaP.fix(0) From d0bdcf0de81c1199cd534c7d75615d3aeaeefd02 Mon Sep 17 00:00:00 2001 From: Lingyan90 Date: Tue, 23 Dec 2025 10:32:20 -0500 Subject: [PATCH 3/5] added comments for help understanding the value difference --- idaes/models/unit_models/tests/test_flash.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/idaes/models/unit_models/tests/test_flash.py b/idaes/models/unit_models/tests/test_flash.py index 31db87df66..c768ec74e3 100644 --- a/idaes/models/unit_models/tests/test_flash.py +++ b/idaes/models/unit_models/tests/test_flash.py @@ -16,7 +16,6 @@ """ from copy import deepcopy import pytest -import pandas as pd from pyomo.environ import ( check_optimal_termination, @@ -256,9 +255,6 @@ def test_get_stream_table_contents(self, btx): "pressure": pytest.approx(101325.0, rel=1e-4), }, } - stable = btx.fs.unit._get_stream_table_contents() - print("\n=== BTXIdeal STREAM TABLE ===") - print(stable) assert stable.to_dict() == expected @pytest.mark.solver @@ -427,7 +423,9 @@ def test_get_stream_table_contents(self, bt_modular): "pressure": getattr(pyunits.pint_registry, "Pa"), }, "Inlet": { - "flow_mol": pytest.approx(1.00, rel=1e-4), + "flow_mol": pytest.approx( + 1.00, rel=1e-4 + ), # This is different from it's property package's (BT_idea) properties_out value of 100 "mole_frac_comp benzene": pytest.approx(0.5, rel=1e-4), "mole_frac_comp toluene": pytest.approx(0.5, rel=1e-4), "temperature": pytest.approx(368, rel=1e-4), @@ -448,9 +446,6 @@ def test_get_stream_table_contents(self, bt_modular): "pressure": pytest.approx(100000.0, rel=1e-4), }, } - stable = bt_modular.fs.unit._get_stream_table_contents() - print("\n=== BTIdealModular STREAM TABLE ===") - print(stable) assert stable.to_dict() == expected @pytest.mark.solver From 372dbf0893885cbf1d9d04d03f701fcef2617a1b Mon Sep 17 00:00:00 2001 From: Lingyan90 Date: Tue, 23 Dec 2025 11:12:25 -0500 Subject: [PATCH 4/5] typos --- idaes/models/unit_models/flash.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idaes/models/unit_models/flash.py b/idaes/models/unit_models/flash.py index 0861ed7d18..1ade61ed99 100644 --- a/idaes/models/unit_models/flash.py +++ b/idaes/models/unit_models/flash.py @@ -362,7 +362,7 @@ def _get_stream_table_contents(self, time_point=0): if self.config.ideal_separation: # If using ideal separation, build the stream table from Ports so that - # all streams use the same naming covention (avoids mismatches with + # all streams use the same naming convention (avoids mismatches with # define_display_vars() across property packages). for n, port_obj in { "Inlet": self.inlet, From 44eb61dd1c391807c30fb3fe8f74c0b08475f112 Mon Sep 17 00:00:00 2001 From: Lingyan90 Date: Fri, 6 Feb 2026 13:43:44 -0500 Subject: [PATCH 5/5] typos --- idaes/models/unit_models/flash.py | 2 +- idaes/models/unit_models/tests/test_flash.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/idaes/models/unit_models/flash.py b/idaes/models/unit_models/flash.py index 1ade61ed99..ebcfa627ec 100644 --- a/idaes/models/unit_models/flash.py +++ b/idaes/models/unit_models/flash.py @@ -386,7 +386,7 @@ def _get_stream_table_contents(self, time_point=0): stream_attributes[n][k + " " + kname] = quant.m stream_attributes["Units"][k + " " + kname] = quant.u else: - # If not using idea separation, we can get outlet state directly + # If not using ideal separation, we can get outlet state directly # from the state blocks sblocks = { "Inlet": self.control_volume.properties_in, diff --git a/idaes/models/unit_models/tests/test_flash.py b/idaes/models/unit_models/tests/test_flash.py index c768ec74e3..b4290ac0f8 100644 --- a/idaes/models/unit_models/tests/test_flash.py +++ b/idaes/models/unit_models/tests/test_flash.py @@ -425,7 +425,7 @@ def test_get_stream_table_contents(self, bt_modular): "Inlet": { "flow_mol": pytest.approx( 1.00, rel=1e-4 - ), # This is different from it's property package's (BT_idea) properties_out value of 100 + ), # This is different from its property package's (BT_ideal) properties_out value of 100 "mole_frac_comp benzene": pytest.approx(0.5, rel=1e-4), "mole_frac_comp toluene": pytest.approx(0.5, rel=1e-4), "temperature": pytest.approx(368, rel=1e-4),