#################################################################################
# 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), and is copyright (c) 2018-2021
# 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.
#################################################################################
"""
This module contains miscellaneous utility functions for use in IDAES models.
"""
from enum import Enum
from pyomo.common.deprecation import deprecated, relocated_module_attribute
import pyomo.environ as pyo
from pyomo.common.config import ConfigBlock
import idaes.logger as idaeslog
from idaes.core.util.tags import svg_tag as svg_tag_new
_log = idaeslog.getLogger(__name__)
relocated_module_attribute(
"get_solver", "idaes.core.solvers.get_solver", version="2.0.0.alpha0"
)
relocated_module_attribute(
"VarLikeExpression",
"idaes.core.base.var_like_expression.VarLikeExpression",
version="2.0.0.alpha0",
)
# Author: Andrew Lee
[docs]def add_object_reference(self, local_name, remote_object):
"""
Method to create a reference in the local model to a remote Pyomo object.
This method should only be used where Pyomo Reference objects are not
suitable (such as for referencing scalar Pyomo objects where the None
index is undesirable).
Args:
local_name : name to use for local reference (str)
remote_object : object to make a reference to
Returns:
None
"""
try:
object.__setattr__(self, local_name, remote_object)
except AttributeError:
raise AttributeError(
"{} failed to construct reference to {} - remote "
"object does not exist.".format(self.name, remote_object)
)
# Author: Jaffer Ghouse
@deprecated(
"idaes.core.util.misc.TagReference will be removed in a future version",
version=1.12,
)
def TagReference(s, description=""):
"""
Create a Pyomo reference with an added description string attribute to
describe the reference. The intended use for these references is to create
a time-indexed reference to variables in a model corresponding to plant
measurment tags.
Args:
s: Pyomo time slice of a variable or expression
description (str): A description the measurment
Returns:
A Pyomo Reference object with an added doc attribute
"""
r = pyo.Reference(s)
r.description = description
return r
def copy_port_values(destination=None, source=None, arc=None, direction="forward"):
"""
Moved to idaes.core.util.initialization.propagate_state.
Leaving redirection function here for deprecation warning.
"""
_log.warning(
"DEPRECATED: copy_port_values has been deprecated. "
"The same functionality can be found in "
"idaes.core.util.initialization.propagate_state."
)
from idaes.core.util.initialization import propagate_state
propagate_state(
destination=destination, source=source, arc=arc, direction=direction
)
@deprecated(
"idaes.core.util.misc.svg_tag has moved to idaes.core.util.tags.svg_tag",
version=1.12,
)
def svg_tag(*args, **kwargs):
"""
Moved to idaes.core.util.tags.svg_tag
Leaving redirection function here for deprecation warning.
"""
return svg_tag_new(*args, **kwargs)
[docs]def set_param_from_config(b, param, config=None, index=None):
"""
Utility method to set parameter value from a config block. This allows for
converting units if required. This method directly sets the value of the
parameter.
This method supports three forms for defining the parameter value:
1. a 2-tuple of the form (value, units) where units are the units that
the value are defined in
2. a float where the float is assumed to be the value of the parameter
value in the base units of the property package
3. a Python Class which has a get_parameter_value method which will
return a 2-tuple of (value, units) based on a lookup of the parameter name
Args:
b - block on which parameter and config block are defined
param - name of parameter as str. Used to find param and config arg
units - units of param object (used if conversion required)
config - (optional) config block to get parameter data from. If
unset, assumes b.config.
index - (optional) used for pure component properties where a single
property may have multiple parameters associated with it.
Returns:
None
"""
if config is None:
try:
config = b.config
except AttributeError:
raise AttributeError(
"{} - set_param_from_config method was not provided with a "
"config argument, but no default Config block exists. Please "
"specify the Config block to use via the config argument.".format(
b.name
)
)
# Check that config is an instance of a Config Block
if not isinstance(config, ConfigBlock):
raise TypeError(
"{} - set_param_from_config - config argument provided is not an "
"instance of a Config Block.".format(b.name)
)
if index is None:
try:
param_obj = getattr(b, param)
except AttributeError:
raise AttributeError(
"{} - set_param_from_config method was provided with param "
"argument {}, but no attribute of that name exists.".format(
b.name, param
)
)
try:
p_data = config.parameter_data[param]
except (KeyError, AttributeError):
raise KeyError(
"{} - set_param_from_config method was provided with param "
"argument {}, but the config block does not contain a "
"value for this parameter.".format(b.name, param)
)
else:
try:
param_obj = getattr(b, param + "_" + index)
except AttributeError:
raise AttributeError(
"{} - set_param_from_config method was provided with param and"
" index arguments {} {}, but no attribute with that "
"combination ({}_{}) exists.".format(b.name, param, index, param, index)
)
try:
p_data = config.parameter_data[param][index]
except (KeyError, AttributeError):
raise KeyError(
"{} - set_param_from_config method was provided with param and"
" index arguments {} {}, but the config block does not contain"
" a value for this parameter and index.".format(b.name, param, index)
)
units = param_obj.get_units()
# Check to see if p_data is callable, and if so, try to call the
# get_parameter_value method to get 2-tuple
if hasattr(p_data, "get_parameter_value"):
p_data = p_data.get_parameter_value(b.local_name, param)
if isinstance(p_data, tuple):
# 11 Dec 2020 - There is currently a bug in Pyomo where trying to
# convert the units of a unitless quantity results in a TypeError.
# To avoid this, we check here for cases where both the parameter and
# user provided value are unitless and bypass unit conversion.
if (units is None or units is pyo.units.dimensionless) and (
p_data[1] is None or p_data[1] is pyo.units.dimensionless
):
param_obj.value = p_data[0]
else:
param_obj.value = pyo.units.convert_value(
p_data[0], from_units=p_data[1], to_units=units
)
else:
_log.debug(
"{} no units provided for parameter {} - assuming default "
"units".format(b.name, param)
)
param_obj.value = p_data
class StrEnum(str, Enum):
"""
Multiple inheritance string-Enum for representing Enums with string values
"""
def __str__(self):
return str(self.value)