Skip to content

Commit c42c0c3

Browse files
Fix initialization of FpcTP with one phase (#1677)
* Fix initialization of FpcTP with one phase * codecov * typo
1 parent 2e7b873 commit c42c0c3

File tree

2 files changed

+124
-10
lines changed

2 files changed

+124
-10
lines changed

idaes/models/properties/modular_properties/base/generic_property.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1691,15 +1691,14 @@ def fix_initialization_states(self):
16911691

16921692
for k in self.values():
16931693
# Also need to deactivate sum of mole fraction constraint
1694-
try:
1694+
if k.is_property_constructed("sum_mole_frac_out"):
16951695
k.sum_mole_frac_out.deactivate()
1696-
except AttributeError:
1697-
pass
1696+
16981697
# Don't need equilibrium constraint for phase component flows
16991698
if (
17001699
"flow_mol_phase_comp" in k.define_state_vars()
17011700
or "mole_frac_phase_comp" in k.define_state_vars()
1702-
):
1701+
) and k.is_property_constructed("equilibrium_constraint"):
17031702
k.equilibrium_constraint.deactivate()
17041703

17051704
if k.is_property_constructed("inherent_equilibrium_constraint") and (
@@ -1793,9 +1792,7 @@ def initialize(
17931792
# When state vars are fixed, check that DoF is 0
17941793
for k in blk.values():
17951794
if degrees_of_freedom(k) != 0:
1796-
# PYLINT-TODO
1797-
# pylint: disable-next=broad-exception-raised
1798-
raise Exception(
1795+
raise InitializationError(
17991796
"State vars fixed but degrees of "
18001797
"freedom for state block is not zero "
18011798
"during initialization."

idaes/models/properties/modular_properties/state_definitions/tests/test_FpcTP.py

Lines changed: 120 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,16 @@
1919
import pytest
2020
import re
2121
from sys import modules
22-
23-
from pyomo.environ import ConcreteModel, Constraint, Expression, Var, units as pyunits
22+
from copy import deepcopy
23+
24+
from pyomo.environ import (
25+
ConcreteModel,
26+
Constraint,
27+
Expression,
28+
value,
29+
Var,
30+
units as pyunits,
31+
)
2432
from pyomo.util.check_units import check_units_equivalent, assert_units_consistent
2533

2634
# Need define_default_scaling_factors, even though it is not used directly
@@ -53,8 +61,9 @@
5361
from idaes.models.properties.modular_properties.phase_equil.bubble_dew import (
5462
IdealBubbleDew,
5563
)
56-
from idaes.core.util.exceptions import ConfigurationError
64+
from idaes.core.util.exceptions import ConfigurationError, InitializationError
5765
import idaes.logger as idaeslog
66+
import idaes.core.util.model_statistics as mstat
5867
from idaes.core.util.model_statistics import degrees_of_freedom, large_residuals_set
5968

6069

@@ -1462,6 +1471,46 @@ def test_phase_equilibrium_legacy_initialization():
14621471
]
14631472

14641473

1474+
@pytest.mark.component
1475+
def test_legacy_initialization_dof_error():
1476+
# This test ensures that the correct exception is
1477+
# raised when there is a degree of freedom error
1478+
# during initialization
1479+
model = ConcreteModel()
1480+
model.fs = FlowsheetBlock(dynamic=False)
1481+
1482+
# Remove the liquid phase and phase equilibrium
1483+
# from the config dict
1484+
config = deepcopy(thermo_config_no_rxn)
1485+
config["phases"].pop("Liq")
1486+
config.pop("phases_in_equilibrium")
1487+
config.pop("phase_equilibrium_state")
1488+
config["components"]["H2O"].pop("phase_equilibrium_form")
1489+
config["components"]["CO2"].pop("phase_equilibrium_form")
1490+
1491+
model.fs.thermo_params = GenericParameterBlock(**config)
1492+
1493+
model.fs.state = model.fs.thermo_params.build_state_block(
1494+
model.fs.time, defined_state=False
1495+
)
1496+
1497+
model.fs.state[0].pressure.fix(101325.0)
1498+
model.fs.state[0].temperature.fix(398.0)
1499+
1500+
model.fs.state[0].flow_mol_phase_comp["Vap", "CO2"].fix(0.005)
1501+
model.fs.state[0].flow_mol_phase_comp["Vap", "H2O"].set_value(0.0005)
1502+
1503+
with pytest.raises(
1504+
InitializationError,
1505+
match=re.escape(
1506+
"State vars fixed but degrees of "
1507+
"freedom for state block is not zero "
1508+
"during initialization."
1509+
),
1510+
):
1511+
model.fs.state.initialize(state_vars_fixed=True)
1512+
1513+
14651514
@pytest.mark.component
14661515
def test_phase_equilibrium_initializer_object():
14671516
# Create a pyomo model object
@@ -1504,3 +1553,71 @@ def test_phase_equilibrium_initializer_object():
15041553
"fs.state[0.0].equilibrium_constraint[Vap,Liq,H2O]",
15051554
"fs.state[0.0].equilibrium_constraint[Vap,Liq,CO2]",
15061555
]
1556+
1557+
1558+
@pytest.mark.component
1559+
def test_initializer_object_single_phase():
1560+
# This test ensures that FpcTP state variables can be
1561+
# initialized even if only a single phase is present
1562+
model = ConcreteModel()
1563+
model.fs = FlowsheetBlock(dynamic=False)
1564+
1565+
# Remove the liquid phase and phase equilibrium
1566+
# from the config dict
1567+
config = deepcopy(thermo_config_no_rxn)
1568+
config["phases"].pop("Liq")
1569+
config.pop("phases_in_equilibrium")
1570+
config.pop("phase_equilibrium_state")
1571+
config["components"]["H2O"].pop("phase_equilibrium_form")
1572+
config["components"]["CO2"].pop("phase_equilibrium_form")
1573+
1574+
model.fs.thermo_params = GenericParameterBlock(**config)
1575+
1576+
model.fs.state = model.fs.thermo_params.build_state_block(
1577+
model.fs.time, defined_state=False
1578+
)
1579+
1580+
model.fs.state[0].pressure.set_value(101325.0)
1581+
model.fs.state[0].temperature.set_value(398.0)
1582+
1583+
model.fs.state[0].flow_mol_phase_comp["Vap", "CO2"].set_value(0.005)
1584+
model.fs.state[0].flow_mol_phase_comp["Vap", "H2O"].set_value(0.0005)
1585+
1586+
assert_units_consistent(model)
1587+
# We expect 4 state variables: T, P, and two pc flows,
1588+
# and 2 non-state variables in mole_frac_phase_comp
1589+
# Because T and P don't appear in any constraints,
1590+
# they are not counted in degrees_of_freedom
1591+
vars_not_in_constraints = mstat.variables_not_in_activated_constraints_set(
1592+
model.fs.state[0]
1593+
)
1594+
assert len(vars_not_in_constraints) == 2
1595+
assert model.fs.state[0].pressure in vars_not_in_constraints
1596+
assert model.fs.state[0].temperature in vars_not_in_constraints
1597+
1598+
assert degrees_of_freedom(model) == 2
1599+
1600+
initializer = model.fs.state.default_initializer()
1601+
1602+
initializer.initialize(model.fs.state)
1603+
1604+
# Check that degrees of freedom are still the same
1605+
vars_not_in_constraints = mstat.variables_not_in_activated_constraints_set(
1606+
model.fs.state[0]
1607+
)
1608+
assert len(vars_not_in_constraints) == 2
1609+
assert model.fs.state[0].pressure in vars_not_in_constraints
1610+
assert model.fs.state[0].temperature in vars_not_in_constraints
1611+
1612+
assert degrees_of_freedom(model) == 2
1613+
1614+
assert value(model.fs.state[0].pressure) == 101325.0
1615+
assert value(model.fs.state[0].temperature) == 398.0
1616+
assert value(model.fs.state[0].flow_mol_phase_comp["Vap", "CO2"]) == 0.005
1617+
assert value(model.fs.state[0].flow_mol_phase_comp["Vap", "H2O"]) == 0.0005
1618+
assert value(model.fs.state[0].mole_frac_phase_comp["Vap", "CO2"]) == pytest.approx(
1619+
5 / 5.5
1620+
)
1621+
assert value(model.fs.state[0].mole_frac_phase_comp["Vap", "H2O"]) == pytest.approx(
1622+
0.5 / 5.5
1623+
)

0 commit comments

Comments
 (0)