-
Notifications
You must be signed in to change notification settings - Fork 234
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
base: main
Are you sure you want to change the base?
Changes from all commits
43982e5
00576ac
1adb5b2
0af89d1
f689ae1
288a39e
9c512e8
0d4d244
ff9a777
603c4b5
086e80f
91a0f64
4bc4aea
40ac61a
11da999
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An explanation of how this is done is important - some of this could be done by expanding the sections below. |
||
|
||
Degrees of Freedom | ||
------------------ | ||
|
||
Stream Scaler blocks generally have zero degrees of freedom. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looking at the code, there is one degree of freedom (and an additional variable). |
||
|
||
Model Structure | ||
--------------- | ||
|
||
Stream Scaler Blocks consists of a single StateBlock (named properties), each with an inlet and outlet port. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not correct from reading the code. The inlet state has a different name, and there is a separate (empty) outlet Block. |
||
|
||
Additional Constraints | ||
---------------------- | ||
|
||
Stream Scaler Blocks write no additional constraints to the model. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is also not correct - the model is adding constraints. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, it actually isn't . It forwards There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or rather, I should say no additional constraints* (besides those naturally occurring in |
||
|
||
Variables | ||
--------- | ||
|
||
Stream Scaler blocks add no additional Variables. | ||
|
||
.. module:: idaes.models.unit_models.stream_scaler | ||
|
||
|
||
Initialization | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do these actually exist? |
||
-------------- | ||
|
||
.. autoclass:: StreamScalerInitializer | ||
:members: initialization_routine | ||
|
||
StreamScaler Class | ||
------------------ | ||
|
||
.. autoclass:: StreamScaler | ||
:members: | ||
|
||
StreamScalerData Class | ||
---------------------- | ||
|
||
.. autoclass:: StreamScalerData | ||
:members: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,6 +40,7 @@ | |
) | ||
from .shell_and_tube_1d import ShellAndTube1D, ShellAndTubeInitializer | ||
from .skeleton_model import SkeletonUnitModel, SkeletonUnitModelData | ||
from .stream_scaler import StreamScaler | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We generally include both the main class and the data class here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay thanks for the feedback |
||
from .statejunction import StateJunction, StateJunctionInitializer | ||
from .stoichiometric_reactor import StoichiometricReactor | ||
from .translator import Translator | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,239 @@ | ||
################################################################################# | ||
# 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, | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These pylint issues need to be addressed for the tests to pass. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On it! |
||
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" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should @tannerpolley be one of the authors here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I actually didnt build the actual unit model itself and didn't edit any of the code here. I was just asked to implement the integration of the unit model into the main repo |
||
|
||
|
||
# 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 | ||
|
||
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.inlet_block = self.config.property_package.build_state_block( | ||
self.flowsheet().time, doc="Material properties at inlet", **tmp_dict | ||
) | ||
self.outlet_block = 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.inlet_block) | ||
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.outlet_block.add_component( | ||
var_name, VarLikeExpression(var.index_set(), rule=rule) | ||
) | ||
expr = getattr(self.outlet_block, 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. | ||
""" | ||
# init_log = idaeslog.getInitLogger(blk.name, outlvl, tag="unit") | ||
# solve_log = idaeslog.getSolveLogger(blk.name, outlvl, tag="unit") | ||
|
||
# Create solver | ||
|
||
# Initialize inlet state blocks | ||
flags = blk.inlet_block.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.inlet_block.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 | ||
scale = 1 / self.multiplier.value | ||
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you meant to change this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this was an intended change that I asked Dan about. When I ran build.py, it would timeout every time. He said it was okay to change this so it could be a topic of discussion