From e778dc6f9656fb1d22c05816b670285bdee7f566 Mon Sep 17 00:00:00 2001 From: Nishant Giridhar Date: Fri, 4 Oct 2024 20:08:56 -0400 Subject: [PATCH 01/10] Allow construction of nested time domain from config.time_set --- idaes/core/base/flowsheet_model.py | 60 ++++++++++++++++++------------ 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/idaes/core/base/flowsheet_model.py b/idaes/core/base/flowsheet_model.py index b9ff3a63ca..c1379acdcf 100644 --- a/idaes/core/base/flowsheet_model.py +++ b/idaes/core/base/flowsheet_model.py @@ -287,6 +287,31 @@ def _get_stream_table_contents(self, time_point=0): return self.stream_table(time_point) def _setup_dynamics(self): + def _create_time_domain(): + if self.config.dynamic: + # Check if time_set has at least two points + if len(self.config.time_set) < 2: + # Check if time_set is at default value + if self.config.time_set == [0.0]: + # If default, set default end point to be 1.0 + self.config.time_set = [0.0, 1.0] + else: + # Invalid user input, raise Exception + raise DynamicError( + "Flowsheet provided with invalid " + "time_set attribute - must have at " + "least two values (start and end)." + ) + # For dynamics, need a ContinuousSet + self._time = ContinuousSet(initialize=self.config.time_set) + else: + # For steady-state, use an ordered Set + self._time = pe.Set(initialize=self.config.time_set, ordered=True) + self._time_units = self.config.time_units + + # Set time config argument as reference to time domain + self.config.time = self._time + # Look for parent flowsheet fs = self.flowsheet() @@ -342,35 +367,24 @@ def _setup_dynamics(self): "{} was set as a dynamic flowsheet, but time domain " "provided was not a ContinuousSet.".format(self.name) ) + + if self.config.dynamic is False and not isinstance( + self.config.time, pe.Set + ): + raise DynamicError( + "{} was set as a steady-state flowsheet, but time domain " + "provided was not a Set.".format(self.name) + ) add_object_reference(self, "_time", self.config.time) self._time_units = self.config.time_units else: # If no parent flowsheet, set up time domain if fs is None: # Create time domain - if self.config.dynamic: - # Check if time_set has at least two points - if len(self.config.time_set) < 2: - # Check if time_set is at default value - if self.config.time_set == [0.0]: - # If default, set default end point to be 1.0 - self.config.time_set = [0.0, 1.0] - else: - # Invalid user input, raise Exception - raise DynamicError( - "Flowsheet provided with invalid " - "time_set attribute - must have at " - "least two values (start and end)." - ) - # For dynamics, need a ContinuousSet - self._time = ContinuousSet(initialize=self.config.time_set) - else: - # For steady-state, use an ordered Set - self._time = pe.Set(initialize=self.config.time_set, ordered=True) - self._time_units = self.config.time_units - - # Set time config argument as reference to time domain - self.config.time = self._time + _create_time_domain() + elif self.config.time_set is not None: + # Create time domain from config.time_set + _create_time_domain() else: # Set time config argument to parent time self.config.time = fs.time From 8ecc4c7d32ff996250272f0a57a96e3aaec4d5ee Mon Sep 17 00:00:00 2001 From: Nishant Giridhar Date: Fri, 4 Oct 2024 20:37:02 -0400 Subject: [PATCH 02/10] Added tests for different time domains in nested flowsheets --- idaes/core/base/tests/test_flowsheet_model.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/idaes/core/base/tests/test_flowsheet_model.py b/idaes/core/base/tests/test_flowsheet_model.py index dfbb581375..8f8d6ff9d6 100644 --- a/idaes/core/base/tests/test_flowsheet_model.py +++ b/idaes/core/base/tests/test_flowsheet_model.py @@ -400,6 +400,29 @@ def test_dynamic_external_time(self): assert m.fs.sub.config.time is m.s assert m.fs.sub.time_units == units.minute + @pytest.mark.unit + def test_dynamic_nested_time(self): + m = ConcreteModel() + m.s1 = ContinuousSet(initialize=[4, 5]) + m.s2 = ContinuousSet(initialize=[1,2,3]) + m.fs = FlowsheetBlock(dynamic=True, time_units=units.s) + m.fs.sub = FlowsheetBlock(dynamic=True, time=m.s2, time_units=units.s) + + assert m.fs.sub.config.dynamic is True + assert isinstance(m.fs.sub.time, ContinuousSet) + assert m.fs.sub.time_units == units.s + + @pytest.mark.unit + def test_dynamic_nested_time_from_time_set(self): + m = ConcreteModel() + m.fs = FlowsheetBlock(dynamic=True, time_set = [1,2,3], time_units=units.s) + m.fs.sub = FlowsheetBlock(dynamic=True, time_set = [1, 2], time_units=units.s) + + assert m.fs.sub.config.dynamic is True + assert isinstance(m.fs.sub.time, ContinuousSet) + assert m.fs.sub.time_units is units.s + + @pytest.mark.unit def test_dynamic_external_time_invalid(self): m = ConcreteModel() From 78551992d358f749ebfd5a1f01b96e3dd392411b Mon Sep 17 00:00:00 2001 From: Nishant Giridhar Date: Fri, 4 Oct 2024 21:00:23 -0400 Subject: [PATCH 03/10] Added test to create nested time indexed SS flowsheet in dynamic parent --- idaes/core/base/tests/test_flowsheet_model.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/idaes/core/base/tests/test_flowsheet_model.py b/idaes/core/base/tests/test_flowsheet_model.py index 8f8d6ff9d6..57094db2cf 100644 --- a/idaes/core/base/tests/test_flowsheet_model.py +++ b/idaes/core/base/tests/test_flowsheet_model.py @@ -422,6 +422,16 @@ def test_dynamic_nested_time_from_time_set(self): assert isinstance(m.fs.sub.time, ContinuousSet) assert m.fs.sub.time_units is units.s + @pytest.mark.unit + def test_dynamic_parent_time_indexed_ss_child(self): + m = ConcreteModel() + m.fs = FlowsheetBlock(dynamic=True, time_set = [1,2,3], time_units=units.s) + m.fs.sub = FlowsheetBlock(dynamic=False, time_set = [0, 1], time_units=units.dimensionless) + + assert m.fs.sub.config.dynamic is False + assert isinstance(m.fs.sub.time, Set) + assert m.fs.sub.time_units == units.dimensionless + @pytest.mark.unit def test_dynamic_external_time_invalid(self): From 71af0da20a81fd154b14c9d1b325074c0a085cad Mon Sep 17 00:00:00 2001 From: Nishant Giridhar Date: Sat, 19 Oct 2024 17:59:16 -0400 Subject: [PATCH 04/10] Add comments + remove check for dynamic sub flowsheet in SS parent flowsheet --- idaes/core/base/flowsheet_model.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/idaes/core/base/flowsheet_model.py b/idaes/core/base/flowsheet_model.py index c1379acdcf..623a55b844 100644 --- a/idaes/core/base/flowsheet_model.py +++ b/idaes/core/base/flowsheet_model.py @@ -368,13 +368,6 @@ def _create_time_domain(): "provided was not a ContinuousSet.".format(self.name) ) - if self.config.dynamic is False and not isinstance( - self.config.time, pe.Set - ): - raise DynamicError( - "{} was set as a steady-state flowsheet, but time domain " - "provided was not a Set.".format(self.name) - ) add_object_reference(self, "_time", self.config.time) self._time_units = self.config.time_units else: @@ -382,6 +375,7 @@ def _create_time_domain(): if fs is None: # Create time domain _create_time_domain() + # Creates a new time domain for a sub-flowsheet with user provided time domain elif self.config.time_set is not None: # Create time domain from config.time_set _create_time_domain() From 03bbc3f26e78ffd002f28e12d41538b35b0eaafd Mon Sep 17 00:00:00 2001 From: Nishant Giridhar Date: Sat, 19 Oct 2024 18:35:02 -0400 Subject: [PATCH 05/10] Updated tests --- idaes/core/base/tests/test_flowsheet_model.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/idaes/core/base/tests/test_flowsheet_model.py b/idaes/core/base/tests/test_flowsheet_model.py index 57094db2cf..dd94fec3d3 100644 --- a/idaes/core/base/tests/test_flowsheet_model.py +++ b/idaes/core/base/tests/test_flowsheet_model.py @@ -409,7 +409,7 @@ def test_dynamic_nested_time(self): m.fs.sub = FlowsheetBlock(dynamic=True, time=m.s2, time_units=units.s) assert m.fs.sub.config.dynamic is True - assert isinstance(m.fs.sub.time, ContinuousSet) + assert m.fs.sub.time is m.s2 assert m.fs.sub.time_units == units.s @pytest.mark.unit @@ -420,17 +420,19 @@ def test_dynamic_nested_time_from_time_set(self): assert m.fs.sub.config.dynamic is True assert isinstance(m.fs.sub.time, ContinuousSet) + assert list(m.fs.sub.time) == [1, 2] assert m.fs.sub.time_units is units.s @pytest.mark.unit def test_dynamic_parent_time_indexed_ss_child(self): m = ConcreteModel() m.fs = FlowsheetBlock(dynamic=True, time_set = [1,2,3], time_units=units.s) - m.fs.sub = FlowsheetBlock(dynamic=False, time_set = [0, 1], time_units=units.dimensionless) + m.fs.sub = FlowsheetBlock(dynamic=False, time_set = [0, 1], time_units=units.min) assert m.fs.sub.config.dynamic is False assert isinstance(m.fs.sub.time, Set) - assert m.fs.sub.time_units == units.dimensionless + assert list(m.fs.sub.time) == [0, 1] + assert m.fs.sub.time_units == units.min @pytest.mark.unit From 77c2f377ddc251bf11d86fb78bd5a17299228651 Mon Sep 17 00:00:00 2001 From: Nishant Giridhar Date: Tue, 22 Oct 2024 11:05:20 -0400 Subject: [PATCH 06/10] update formatting with black --- idaes/core/base/flowsheet_model.py | 2 +- idaes/core/base/tests/test_flowsheet_model.py | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/idaes/core/base/flowsheet_model.py b/idaes/core/base/flowsheet_model.py index 623a55b844..86e2ede574 100644 --- a/idaes/core/base/flowsheet_model.py +++ b/idaes/core/base/flowsheet_model.py @@ -367,7 +367,7 @@ def _create_time_domain(): "{} was set as a dynamic flowsheet, but time domain " "provided was not a ContinuousSet.".format(self.name) ) - + add_object_reference(self, "_time", self.config.time) self._time_units = self.config.time_units else: diff --git a/idaes/core/base/tests/test_flowsheet_model.py b/idaes/core/base/tests/test_flowsheet_model.py index dd94fec3d3..381a43a6df 100644 --- a/idaes/core/base/tests/test_flowsheet_model.py +++ b/idaes/core/base/tests/test_flowsheet_model.py @@ -404,7 +404,7 @@ def test_dynamic_external_time(self): def test_dynamic_nested_time(self): m = ConcreteModel() m.s1 = ContinuousSet(initialize=[4, 5]) - m.s2 = ContinuousSet(initialize=[1,2,3]) + m.s2 = ContinuousSet(initialize=[1, 2, 3]) m.fs = FlowsheetBlock(dynamic=True, time_units=units.s) m.fs.sub = FlowsheetBlock(dynamic=True, time=m.s2, time_units=units.s) @@ -415,8 +415,8 @@ def test_dynamic_nested_time(self): @pytest.mark.unit def test_dynamic_nested_time_from_time_set(self): m = ConcreteModel() - m.fs = FlowsheetBlock(dynamic=True, time_set = [1,2,3], time_units=units.s) - m.fs.sub = FlowsheetBlock(dynamic=True, time_set = [1, 2], time_units=units.s) + m.fs = FlowsheetBlock(dynamic=True, time_set=[1, 2, 3], time_units=units.s) + m.fs.sub = FlowsheetBlock(dynamic=True, time_set=[1, 2], time_units=units.s) assert m.fs.sub.config.dynamic is True assert isinstance(m.fs.sub.time, ContinuousSet) @@ -426,15 +426,14 @@ def test_dynamic_nested_time_from_time_set(self): @pytest.mark.unit def test_dynamic_parent_time_indexed_ss_child(self): m = ConcreteModel() - m.fs = FlowsheetBlock(dynamic=True, time_set = [1,2,3], time_units=units.s) - m.fs.sub = FlowsheetBlock(dynamic=False, time_set = [0, 1], time_units=units.min) + m.fs = FlowsheetBlock(dynamic=True, time_set=[1, 2, 3], time_units=units.s) + m.fs.sub = FlowsheetBlock(dynamic=False, time_set=[0, 1], time_units=units.min) assert m.fs.sub.config.dynamic is False assert isinstance(m.fs.sub.time, Set) assert list(m.fs.sub.time) == [0, 1] assert m.fs.sub.time_units == units.min - @pytest.mark.unit def test_dynamic_external_time_invalid(self): m = ConcreteModel() From 891b85738c6a26b6d4accf59ce74e1315ae4c3db Mon Sep 17 00:00:00 2001 From: Nishant Giridhar Date: Tue, 22 Oct 2024 13:32:28 -0400 Subject: [PATCH 07/10] Sub-flowsheets with unspecified time inherit time from parent --- idaes/core/base/flowsheet_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idaes/core/base/flowsheet_model.py b/idaes/core/base/flowsheet_model.py index 86e2ede574..82ccb3cf54 100644 --- a/idaes/core/base/flowsheet_model.py +++ b/idaes/core/base/flowsheet_model.py @@ -376,7 +376,7 @@ def _create_time_domain(): # Create time domain _create_time_domain() # Creates a new time domain for a sub-flowsheet with user provided time domain - elif self.config.time_set is not None: + elif self.config.time_set not in [None, [0]]: # Create time domain from config.time_set _create_time_domain() else: From c322abed11a0367d0098d678a235a692eaf44702 Mon Sep 17 00:00:00 2001 From: Nishant Giridhar Date: Tue, 22 Oct 2024 15:26:33 -0400 Subject: [PATCH 08/10] Fix test to use user provided time for parent flowsheet --- idaes/core/base/tests/test_flowsheet_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idaes/core/base/tests/test_flowsheet_model.py b/idaes/core/base/tests/test_flowsheet_model.py index 381a43a6df..1db6ba51c1 100644 --- a/idaes/core/base/tests/test_flowsheet_model.py +++ b/idaes/core/base/tests/test_flowsheet_model.py @@ -405,7 +405,7 @@ def test_dynamic_nested_time(self): m = ConcreteModel() m.s1 = ContinuousSet(initialize=[4, 5]) m.s2 = ContinuousSet(initialize=[1, 2, 3]) - m.fs = FlowsheetBlock(dynamic=True, time_units=units.s) + m.fs = FlowsheetBlock(dynamic=True, time=m.s1, time_units=units.minute) m.fs.sub = FlowsheetBlock(dynamic=True, time=m.s2, time_units=units.s) assert m.fs.sub.config.dynamic is True From 5ceb39a8a7997f37f15fe1516c859b1707f0a687 Mon Sep 17 00:00:00 2001 From: Nishant Giridhar Date: Tue, 19 Nov 2024 14:42:12 -0500 Subject: [PATCH 09/10] Changed default config for time_set from [0] to None --- idaes/core/base/flowsheet_model.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/idaes/core/base/flowsheet_model.py b/idaes/core/base/flowsheet_model.py index 82ccb3cf54..d5a3b82acf 100644 --- a/idaes/core/base/flowsheet_model.py +++ b/idaes/core/base/flowsheet_model.py @@ -139,7 +139,7 @@ class FlowsheetBlockData(ProcessBlockData): CONFIG.declare( "time_set", ConfigValue( - default=[0], + default=None, domain=ListOf(float), description="Set of points for initializing time domain", doc="""Set of points for initializing time domain. This should be a @@ -373,10 +373,13 @@ def _create_time_domain(): else: # If no parent flowsheet, set up time domain if fs is None: + # Set default time_set to [0] if not provided + if self.config.time_set is None: + self.config.time_set = [0] # Create time domain _create_time_domain() # Creates a new time domain for a sub-flowsheet with user provided time domain - elif self.config.time_set not in [None, [0]]: + elif self.config.time_set is not None: # Create time domain from config.time_set _create_time_domain() else: From 5cc5765f96b758f1f13456c8871fce9750004d29 Mon Sep 17 00:00:00 2001 From: Nishant Giridhar Date: Tue, 19 Nov 2024 14:42:46 -0500 Subject: [PATCH 10/10] Updated test_config --- idaes/core/base/tests/test_flowsheet_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/idaes/core/base/tests/test_flowsheet_model.py b/idaes/core/base/tests/test_flowsheet_model.py index 1db6ba51c1..87299ee5f1 100644 --- a/idaes/core/base/tests/test_flowsheet_model.py +++ b/idaes/core/base/tests/test_flowsheet_model.py @@ -55,7 +55,7 @@ def test_config(self, model): assert len(model.fs.config) == 5 assert model.fs.config.dynamic is useDefault assert model.fs.config.time is None - assert model.fs.config.time_set == [0] + assert model.fs.config.time_set == None assert model.fs.config.default_property_package is None assert model.fs.config.time_units is None