|
19 | 19 | import pytest
|
20 | 20 | import re
|
21 | 21 | 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 | +) |
24 | 32 | from pyomo.util.check_units import check_units_equivalent, assert_units_consistent
|
25 | 33 |
|
26 | 34 | # Need define_default_scaling_factors, even though it is not used directly
|
|
53 | 61 | from idaes.models.properties.modular_properties.phase_equil.bubble_dew import (
|
54 | 62 | IdealBubbleDew,
|
55 | 63 | )
|
56 |
| -from idaes.core.util.exceptions import ConfigurationError |
| 64 | +from idaes.core.util.exceptions import ConfigurationError, InitializationError |
57 | 65 | import idaes.logger as idaeslog
|
| 66 | +import idaes.core.util.model_statistics as mstat |
58 | 67 | from idaes.core.util.model_statistics import degrees_of_freedom, large_residuals_set
|
59 | 68 |
|
60 | 69 |
|
@@ -1462,6 +1471,46 @@ def test_phase_equilibrium_legacy_initialization():
|
1462 | 1471 | ]
|
1463 | 1472 |
|
1464 | 1473 |
|
| 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 | + |
1465 | 1514 | @pytest.mark.component
|
1466 | 1515 | def test_phase_equilibrium_initializer_object():
|
1467 | 1516 | # Create a pyomo model object
|
@@ -1504,3 +1553,71 @@ def test_phase_equilibrium_initializer_object():
|
1504 | 1553 | "fs.state[0.0].equilibrium_constraint[Vap,Liq,H2O]",
|
1505 | 1554 | "fs.state[0.0].equilibrium_constraint[Vap,Liq,CO2]",
|
1506 | 1555 | ]
|
| 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