Skip to content

Commit

Permalink
Fixing handling of useDefault in lumped capacitance HX model (#1259)
Browse files Browse the repository at this point in the history
* Fixing usage of config.property_package

* Fixing issues in HX_LC model

* Revert "Fixing issues in HX_LC model"

This reverts commit 5a751db.

* Fixing issues with HX_LC

* Fixing typo

---------

Co-authored-by: Ludovico Bianchi <[email protected]>
  • Loading branch information
andrewlee94 and lbianchi-lbl authored Sep 1, 2023
1 parent ae6db24 commit 53e9feb
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 15 deletions.
63 changes: 55 additions & 8 deletions idaes/models/unit_models/heat_exchanger_lc.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from pyomo.common.config import ConfigValue
from idaes.core import declare_process_block_class, useDefault
from idaes.core.util.config import DefaultBool
from idaes.core.util.exceptions import ConfigurationError, IdaesError
from idaes.core.util.exceptions import ConfigurationError, IdaesError, DynamicError
from .heat_exchanger import HeatExchangerData


Expand Down Expand Up @@ -113,6 +113,60 @@ def _add_wall_variables(self):
units=ua_units,
)

def _setup_dynamics(self):
"""
The Lumped Capacitance Heat Exchanger model is different from other
unit models in that it allows for part of the heat balance to be dynamic
whilst the control volumes are steady state. Thus, we need a custom
_setup_dynamics method.
Args:
None
Returns:
None
"""
# Get flowsheet dynamic flag
dynamic = self.flowsheet().config.dynamic

# First, check the dynamic_heat_balance argument
if self.config.dynamic_heat_balance is useDefault:
# If use default, use flowsheet flag
self.config.dynamic_heat_balance = dynamic
elif self.config.dynamic_heat_balance and not dynamic:
# If True, flowsheet must also be dynamic
raise DynamicError(
"{} trying to declare a dynamic model within "
"a steady-state flowsheet. This is not "
"supported by the IDAES framework. Try "
"creating a dynamic flowsheet instead, and "
"declaring some models as steady-state.".format(self.name)
)

# Next, check the dynamic flag
if self.config.dynamic == useDefault:
# Use same setting as dynamic_heat_balance
self.config.dynamic = self.config.dynamic_heat_balance
elif self.config.dynamic and not self.config.dynamic_heat_balance:
# If True, must also have dynamic_heat_balance = True
raise ConfigurationError(
"{} dynamic can only be True if dynamic_heat_balance "
"is also True.".format(self.name)
)

# Set and validate has_holdup argument
if self.config.has_holdup == useDefault:
# Default to same value as dynamic flag
self.config.has_holdup = self.config.dynamic
elif self.config.has_holdup is False:
if self.config.dynamic is True:
# Dynamic model must have has_holdup = True
raise ConfigurationError(
"{} invalid arguments for dynamic and has_holdup. "
"If dynamic = True, has_holdup must also be True "
"(was False)".format(self.name)
)

def _add_wall_variable_constraints(self):
@self.Constraint(
self.flowsheet().config.time,
Expand Down Expand Up @@ -206,13 +260,6 @@ def build(self):
temp_units = s1_metadata.get_derived_units("temperature")
time_units = s1_metadata.get_derived_units("time")

if not self.flowsheet().config.dynamic:
raise ConfigurationError(
"{} dynamic heat balance cannot be "
"used with a steady-state "
"flowsheet".format(self.name)
)

self.dT_wall_dt = DerivativeVar(
self.temperature_wall,
wrt=self.flowsheet().config.time,
Expand Down
101 changes: 94 additions & 7 deletions idaes/models/unit_models/tests/test_heat_exchanger_lc.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

from idaes.core.util.model_statistics import degrees_of_freedom
from idaes.core.solvers import get_solver
from idaes.core.util.exceptions import ConfigurationError, IdaesError
from idaes.core.util.exceptions import DynamicError, ConfigurationError, IdaesError

from idaes.core.util.testing import PhysicalParameterTestBlock, initialization_tester

Expand All @@ -59,7 +59,6 @@
from idaes.models.unit_models.heat_exchanger import delta_temperature_lmtd_callback
from idaes.models.properties.general_helmholtz import helmholtz_available
from idaes.core.initialization import (
BlockTriangularizationInitializer,
InitializationStatus,
)

Expand Down Expand Up @@ -368,12 +367,19 @@ def test_solve(self, model):
assert check_optimal_termination(results)

@pytest.mark.unit
def test_static_flowsheet(self, static_flowsheet_model):
m = static_flowsheet_model
def test_dynamic_heat_in_static_flowsheet(self):
m = ConcreteModel()
m.fs = FlowsheetBlock(dynamic=False)

m.fs.properties = PhysicalParameterTestBlock()

with pytest.raises(
ConfigurationError,
match="dynamic heat balance cannot be used with a "
"steady-state flowsheet",
DynamicError,
match="trying to declare a dynamic model within "
"a steady-state flowsheet. This is not "
"supported by the IDAES framework. Try "
"creating a dynamic flowsheet instead, and "
"declaring some models as steady-state.",
):
m.fs.unit = HeatExchangerLumpedCapacitance(
hot_side_name="shell",
Expand All @@ -384,6 +390,87 @@ def test_static_flowsheet(self, static_flowsheet_model):
dynamic_heat_balance=True,
)

@pytest.mark.unit
def test_dynamic_cv_wo_dynamic_heat(self):
m = ConcreteModel()
m.fs = FlowsheetBlock(dynamic=False)

m.fs.properties = PhysicalParameterTestBlock()

with pytest.raises(
ConfigurationError,
match="dynamic can only be True if dynamic_heat_balance " "is also True.",
):
m.fs.unit = HeatExchangerLumpedCapacitance(
hot_side_name="shell",
cold_side_name="tube",
shell={"property_package": m.fs.properties},
tube={"property_package": m.fs.properties},
dynamic=True,
dynamic_heat_balance=False,
)

@pytest.mark.unit
def test_default_in_dynamic_flowsheet(self):
m = ConcreteModel()
m.fs = FlowsheetBlock(dynamic=True, time_set=[0, 1], time_units=pyunits.s)

m.fs.properties = PhysicalParameterTestBlock()

m.fs.unit = HeatExchangerLumpedCapacitance(
hot_side_name="shell",
cold_side_name="tube",
shell={"property_package": m.fs.properties},
tube={"property_package": m.fs.properties},
)

assert m.fs.unit.config.dynamic_heat_balance
assert m.fs.unit.config.dynamic
assert m.fs.unit.config.has_holdup

@pytest.mark.unit
def test_steady_state_cv_in_dynamic_flowsheet(self):
m = ConcreteModel()
m.fs = FlowsheetBlock(dynamic=True, time_set=[0, 1], time_units=pyunits.s)

m.fs.properties = PhysicalParameterTestBlock()

m.fs.unit = HeatExchangerLumpedCapacitance(
hot_side_name="shell",
cold_side_name="tube",
shell={"property_package": m.fs.properties},
tube={"property_package": m.fs.properties},
dynamic=False,
dynamic_heat_balance=True,
)

assert m.fs.unit.config.dynamic_heat_balance
assert not m.fs.unit.config.dynamic
assert not m.fs.unit.config.has_holdup

@pytest.mark.unit
def test_dynamic_wo_holdup(self):
m = ConcreteModel()
m.fs = FlowsheetBlock(dynamic=True, time_set=[0, 1], time_units=pyunits.s)

m.fs.properties = PhysicalParameterTestBlock()

with pytest.raises(
ConfigurationError,
match="invalid arguments for dynamic and has_holdup. "
"If dynamic = True, has_holdup must also be True "
"\(was False\)",
):
m.fs.unit = HeatExchangerLumpedCapacitance(
hot_side_name="shell",
cold_side_name="tube",
shell={"property_package": m.fs.properties},
tube={"property_package": m.fs.properties},
dynamic=True,
dynamic_heat_balance=True,
has_holdup=False,
)

@pytest.mark.unit
def test_static_heat_balance(self, static_flowsheet_model):
m = static_flowsheet_model
Expand Down

0 comments on commit 53e9feb

Please sign in to comment.