Source code for pyomo.contrib.mpc.modeling.terminal

#  ___________________________________________________________________________
#
#  Pyomo: Python Optimization Modeling Objects
#  Copyright (c) 2008-2024
#  National Technology and Engineering Solutions of Sandia, LLC
#  Under the terms of Contract DE-NA0003525 with National Technology and
#  Engineering Solutions of Sandia, LLC, the U.S. Government retains certain
#  rights in this software.
#  This software is distributed under the 3-clause BSD License.
#  ___________________________________________________________________________

#################################################################################
# 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.
#################################################################################

from pyomo.core.base.componentuid import ComponentUID
from pyomo.core.base.expression import Expression
from pyomo.core.base.set import Set

from pyomo.contrib.mpc.data.series_data import get_indexed_cuid
from pyomo.contrib.mpc.data.scalar_data import ScalarData


def _get_quadratic_penalty_at_time(var, t, target, weight=None):
    if weight is None:
        weight = 1.0
    return weight * (var[t] - target) ** 2


def _get_penalty_expressions_at_time(
    variables, t, target_data, weight_data=None, time_set=None
):
    """A private helper function to process data and construct penalty
    expressions

    """
    if weight_data is None:
        weight_data = ScalarData(ComponentMap((var, 1.0) for var in variables))
    if not isinstance(weight_data, ScalarData):
        # We pass time_set as an argument in case the user provides a
        # ComponentMap of VarData -> values. In this case knowing the
        # time set is necessary to recover the indexed CUID.
        weight_data = ScalarData(weight_data, time_set=time_set)
    if not isinstance(target_data, ScalarData):
        target_data = ScalarData(target_data, time_set=time_set)

    for var in variables:
        if not target_data.contains_key(var):
            raise KeyError(
                "Target data does not contain a key for variable %s" % var.name
            )
        if not weight_data.contains_key(var):
            raise KeyError(
                "Penalty weight data does not contain a key for variable %s" % var.name
            )

    penalties = [
        _get_quadratic_penalty_at_time(
            var,
            t,
            target_data.get_data_from_key(var),
            weight_data.get_data_from_key(var),
        )
        for var in variables
    ]
    return penalties


[docs]def get_penalty_at_time( variables, t, target_data, weight_data=None, time_set=None, variable_set=None ): """Returns an Expression penalizing the deviation of the specified variables at the specified point in time from the specified target Arguments --------- variables: List List of time-indexed variables that will be penalized t: Float Time point at which to apply the penalty target_data: ScalarData ScalarData object containing the target for (at least) the variables to be penalized weight_data: ScalarData (optional) ScalarData object containing the penalty weights for (at least) the variables to be penalized time_set: Set (optional) Time set that indexes the provided variables. This is only used if target or weight data are provided as a ComponentMap with VarData as keys. In this case the Set is necessary to recover the CUIDs used internally as keys variable_set: Set (optional) Set indexing the list of variables provided, if such a set already exists Returns ------- Set, Expression Set indexing the list of variables provided and an Expression, indexed by this set, containing the weighted penalty expressions """ if variable_set is None: variable_set = Set(initialize=range(len(variables))) penalty_expressions = _get_penalty_expressions_at_time( variables, t, target_data, weight_data=weight_data, time_set=time_set ) def penalty_rule(m, i): return penalty_expressions[i] penalty = Expression(variable_set, rule=penalty_rule) return variable_set, penalty
[docs]def get_terminal_penalty( variables, time_set, target_data, weight_data=None, variable_set=None ): """Returns an Expression penalizing the deviation of the specified variables at the final point in time from the specified target Arguments --------- variables: List List of time-indexed variables that will be penalized time_set: Set Time set that indexes the provided variables. Penalties are applied at the last point in this set. target_data: ScalarData ScalarData object containing the target for (at least) the variables to be penalized weight_data: ScalarData (optional) ScalarData object containing the penalty weights for (at least) the variables to be penalized variable_set: Set (optional) Set indexing the list of variables provided, if such a set already exists Returns ------- Set, Expression Set indexing the list of variables provided and an Expression, indexed by this set, containing the weighted penalty expressions """ t = time_set.last() return get_penalty_at_time( variables, t, target_data, weight_data=weight_data, time_set=time_set, variable_set=variable_set, )