Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding StreamScaler unit model, along with the test and rst file. #1517

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
43982e5
pull from MEA development branch
dallan-keylogic Sep 23, 2024
00576ac
Added test file for StreamScaler unit model and added the unit model …
tannerpolley Oct 3, 2024
1adb5b2
pull from MEA development branch
dallan-keylogic Sep 23, 2024
0af89d1
Added test file for StreamScaler unit model and added the unit model …
tannerpolley Oct 3, 2024
f689ae1
Added rst file for Stream Scaler Unit Model
tannerpolley Oct 29, 2024
288a39e
Added stream_scaler.rst to the table of contents
tannerpolley Oct 31, 2024
9c512e8
Created the rst file for the stream_scaler unit model
tannerpolley Oct 31, 2024
0d4d244
Changed the default timeout time from 180 seconds -> 360 seconds due …
tannerpolley Oct 31, 2024
ff9a777
Merge remote-tracking branch 'tannerpolley/stream_scaler_Polley' into…
tannerpolley Oct 31, 2024
603c4b5
Reformatted with Black
tannerpolley Oct 31, 2024
086e80f
Removed unused code flagged by Pylint
tannerpolley Oct 31, 2024
91a0f64
Removed unused code flagged by Pylint
tannerpolley Oct 31, 2024
4bc4aea
Removed unused code flagged by Pylint
tannerpolley Nov 1, 2024
40ac61a
Removed unused code flagged by Pylint
tannerpolley Nov 1, 2024
11da999
Merge remote-tracking branch 'origin/main' into stream_scaler_Polley
tannerpolley Nov 4, 2024
85b1679
Added StreamScalerData class to the init file for unit models
tannerpolley Nov 15, 2024
30565ec
Added Tanner Polley as a co-author
tannerpolley Nov 15, 2024
7fa9c2a
Adjusted the details of the additional constraints
tannerpolley Nov 15, 2024
15a0426
Resolved the test_solution method for btx and removed the comment for…
tannerpolley Nov 15, 2024
194f476
Ran Black on these files
tannerpolley Nov 15, 2024
a96f827
Merge branch 'main' into stream_scaler_Polley
dallan-keylogic Nov 15, 2024
2df7345
Fixed degrees of freedom on doc file
tannerpolley Nov 18, 2024
c957d4a
Merge remote-tracking branch 'origin/stream_scaler_Polley' into strea…
tannerpolley Nov 18, 2024
faced0b
Revised the documentation for Degrees of Freedom for Stream Scaler
tannerpolley Nov 18, 2024
779296e
Removed unnecessary comments
tannerpolley Nov 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,8 @@ def main() -> int:
"-t",
"--timeout",
dest="timeout",
help="Timeout (in seconds) for sphinx-build (default=180)",
default=180,
help="Timeout (in seconds) for sphinx-build (default=360)",
default=360,
tannerpolley marked this conversation as resolved.
Show resolved Hide resolved
type=int,
)
prs.add_argument(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Unit Models
skeleton_unit
statejunction
stoichiometric_reactor
stream_scaler
translator
turbine
valve
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
Stream Scaler Block
===================

Stream Scaler Blocks are used to adjust size of streams to represent, for example, a stream being split across several identical units, which are then all modeled as a single IDAES unit
tannerpolley marked this conversation as resolved.
Show resolved Hide resolved

Degrees of Freedom
------------------

Stream Scaler blocks have one degree of freedom (beyond the state variables in the ``StateBlock`` properties), a ``Var`` called ``multiplier``. It is the factor by which extensive state variables (defined as those having "flow" in their name) are scaled, with ``output_var = multiplier * input_var``.

Model Structure
---------------

Stream Scaler Blocks consists of a single ``StateBlock`` (named properties), each with an inlet and outlet port.

Additional Constraints
----------------------

Stream Scaler Blocks write no additional constraints* (besides those naturally occurring in ``StateBlocks``).

Variables
---------

Stream Scaler blocks add no additional Variables.

.. module:: idaes.models.unit_models.stream_scaler


Initialization
tannerpolley marked this conversation as resolved.
Show resolved Hide resolved
--------------

.. autoclass:: StreamScalerInitializer
:members: initialization_routine

StreamScaler Class
------------------

.. autoclass:: StreamScaler
:members:

StreamScalerData Class
----------------------

.. autoclass:: StreamScalerData
:members:

1 change: 1 addition & 0 deletions idaes/models/unit_models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
)
from .shell_and_tube_1d import ShellAndTube1D, ShellAndTubeInitializer
from .skeleton_model import SkeletonUnitModel, SkeletonUnitModelData
from .stream_scaler import StreamScaler, StreamScalerData
from .statejunction import StateJunction, StateJunctionInitializer
from .stoichiometric_reactor import StoichiometricReactor
from .translator import Translator
Expand Down
244 changes: 244 additions & 0 deletions idaes/models/unit_models/stream_scaler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
#################################################################################
# The Institute for the Design of Advanced Energy Systems Integrated Platform
# Framework (IDAES IP) was produced under the DOE Institute for the
# Design of Advanced Energy Systems (IDAES).
#
# Copyright (c) 2018-2023 by the software owners: The Regents of the
# University of California, through Lawrence Berkeley National Laboratory,
# National Technology & Engineering Solutions of Sandia, LLC, Carnegie Mellon
# University, West Virginia University Research Corporation, et al.
# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md
# for full copyright and license information.
#################################################################################
"""
Unit model to adjust size of streams to represent, for example, a stream being split across several identical units,
which are then all modeled as a single IDAES unit
"""
from functools import partial

from pyomo.environ import (
Block,
PositiveReals,
units as pyunits,
Var,
)
tannerpolley marked this conversation as resolved.
Show resolved Hide resolved
from pyomo.network import Port
from pyomo.common.config import ConfigBlock, ConfigValue, In

from idaes.core import (
declare_process_block_class,
UnitModelBlockData,
useDefault,
)
from idaes.core.util.config import (
is_physical_parameter_block,
)
from idaes.core.base.var_like_expression import VarLikeExpression
from idaes.core.util.tables import create_stream_table_dataframe
import idaes.core.util.scaling as iscale
import idaes.logger as idaeslog

from idaes.models.unit_models.feed import FeedInitializer as StreamScalerInitializer

__author__ = "Douglas Allan, Tanner Polley"


# Set up logger
_log = idaeslog.getLogger(__name__)


@declare_process_block_class("StreamScaler")
class StreamScalerData(UnitModelBlockData):
"""
Unit model to adjust size of streams to represent, for example, a stream being split across several identical units,
which are then all modeled as a single IDAES unit
"""

default_initializer = StreamScalerInitializer
tannerpolley marked this conversation as resolved.
Show resolved Hide resolved

CONFIG = ConfigBlock()
CONFIG.declare(
"dynamic",
ConfigValue(
domain=In([False]),
default=False,
description="Dynamic model flag - must be False",
doc="""Indicates whether this model will be dynamic or not,
**default** = False. Scaler blocks are always steady-state.""",
),
)
CONFIG.declare(
"has_holdup",
ConfigValue(
default=False,
domain=In([False]),
description="Holdup construction flag - must be False",
doc="Scaler blocks do not contain holdup, thus this must be False.",
),
)
CONFIG.declare(
"property_package",
ConfigValue(
default=useDefault,
domain=is_physical_parameter_block,
description="Property package to use for StreamScaler",
doc="""Property parameter object used to define property
calculations, **default** - useDefault.
**Valid values:** {
**useDefault** - use default package from parent model or flowsheet,
**PropertyParameterObject** - a PropertyParameterBlock object.}""",
),
)
CONFIG.declare(
"property_package_args",
ConfigBlock(
implicit=True,
description="Arguments to use for constructing property packages",
doc="""A ConfigBlock with arguments to be passed to a property
block(s) and used when constructing these,
**default** - None.
**Valid values:** {
see property package for documentation.}""",
),
)

def build(self):
"""
General build method for StreamScalerData. This method calls a number
of sub-methods which automate the construction of expected attributes
of unit models.

Inheriting models should call `super().build`.

Args:
None

Returns:
None
"""
# Call super.build()
super(StreamScalerData, self).build()

tmp_dict = dict(**self.config.property_package_args)
tmp_dict["has_phase_equilibrium"] = False
tmp_dict["defined_state"] = True

# Call setup methods from ControlVolumeBlockData
self._get_property_package()
self._get_indexing_sets()

self.properties = self.config.property_package.build_state_block(
self.flowsheet().time, doc="Material properties at inlet", **tmp_dict
)
self.scaled_expressions = Block()
self.multiplier = Var(
initialize=1,
domain=PositiveReals,
units=pyunits.dimensionless,
doc="Factor by which to scale dimensionless streams",
)
self.add_inlet_port(name="inlet", block=self.properties)
self.outlet = Port(doc="Outlet port")

def rule_scale_var(b, *args, var=None):
return self.multiplier * var[args]

def rule_no_scale_var(b, *args, var=None):
return var[args]

for var_name in self.inlet.vars.keys():
var = getattr(self.inlet, var_name)
if "flow" in var_name:
rule = partial(rule_scale_var, var=var)
else:
rule = partial(rule_no_scale_var, var=var)
self.scaled_expressions.add_component(
var_name, VarLikeExpression(var.index_set(), rule=rule)
)
expr = getattr(self.scaled_expressions, var_name)
self.outlet.add(expr, var_name)

def initialize_build(
blk, outlvl=idaeslog.NOTSET, optarg=None, solver=None, hold_state=False
):
"""
Initialization routine for StreamScaler.

Keyword Arguments:
outlvl : sets output level of initialization routine
optarg : solver options dictionary object (default=None, use
default solver options)
solver : str indicating which solver to use during
initialization (default = None, use default solver)
hold_state : flag indicating whether the initialization routine
should unfix any state variables fixed during
initialization, **default** - False. **Valid values:**
**True** - states variables are not unfixed, and a dict of
returned containing flags for which states were fixed
during initialization, **False** - state variables are
unfixed after initialization by calling the release_state
method.

Returns:
If hold_states is True, returns a dict containing flags for which
states were fixed during initialization.
"""

# Create solver

# Initialize inlet state blocks
flags = blk.properties.initialize(
outlvl=outlvl,
optarg=optarg,
solver=solver,
hold_state=True,
)

if hold_state is True:
return flags
else:
blk.release_state(flags, outlvl=outlvl)

def release_state(blk, flags, outlvl=idaeslog.NOTSET):
"""
Method to release state variables fixed during initialization.

Keyword Arguments:
flags : dict containing information of which state variables
were fixed during initialization, and should now be
unfixed. This dict is returned by initialize if
hold_state = True.
outlvl : sets output level of logging

Returns:
None
"""
blk.properties.release_state(flags, outlvl=outlvl)

def _get_stream_table_contents(self, time_point=0):
io_dict = {
"Inlet": self.inlet,
# "Outlet": self.outlet,
}
return create_stream_table_dataframe(io_dict, time_point=time_point)

def calculate_scaling_factors(self):
# Scaling factors for the property block are calculated automatically
super().calculate_scaling_factors()

# Need to pass on scaling factors from the property block to the outlet
# VarLikeExpressions so arcs get scaled right
if self.multiplier.value == 0:
default = 1
else:
default = 1 / self.multiplier.value

scale = iscale.get_scaling_factor(
self.multiplier, default=default, warning=False
)
for var_name in self.inlet.vars.keys():
var = getattr(self.inlet, var_name)
outlet_expr = getattr(self.outlet, var_name)
for key, subvar in var.items():
sf = iscale.get_scaling_factor(subvar, default=1, warning=True)
iscale.set_scaling_factor(outlet_expr[key], scale * sf)
Loading
Loading