# Path: calliope/backend/pyomo/util.py
# @memoize
# def get_param(backend_model, var, dims):
#     """
#     Get an input parameter held in a Pyomo object, or held in the defaults
#     dictionary if that Pyomo object doesn't exist.
# 
#     Parameters
#     ----------
#     backend_model : Pyomo model instance
#     var : str
#     dims : single value or tuple
# 
#     """
#     try:
#         return getattr(backend_model, var)[dims]
#     except AttributeError:  # i.e. parameter doesn't exist at all
#         logger.debug(
#             "get_param: var {} and dims {} leading to default lookup".format(var, dims)
#         )
#         return backend_model.__calliope_defaults[var]
#     except KeyError:  # try removing timestep
#         try:
#             if len(dims) > 2:
#                 return getattr(backend_model, var)[dims[:-1]]
#             else:
#                 return getattr(backend_model, var)[dims[0]]
#         except KeyError:  # Static default value
#             logger.debug(
#                 "get_param: var {} and dims {} leading to default lookup".format(
#                     var, dims
#                 )
#             )
#             return backend_model.__calliope_defaults[var]
# 
# @memoize
# def get_conversion_plus_io(backend_model, tier):
#     """
#     from a carrier_tier, return the primary tier (of `in`, `out`) and
#     corresponding decision variable (`carrier_con` and `carrier_prod`, respectively)
#     """
#     if "out" in tier:
#         return "out", backend_model.carrier_prod
#     elif "in" in tier:
#         return "in", backend_model.carrier_con


import pyomo.core as po
from calliope.backend.pyomo.util import (
    get_param,
    get_conversion_plus_io,
)

Conversion plus technology constraints.

"""




def balance_conversion_plus_primary_constraint_rule(
    backend_model, node, tech, timestep
):
    """
    Balance energy carrier consumption and production for carrier_in and carrier_out

    .. container:: scrolling-wrapper

        .. math::

            \\sum_{loc::tech::carrier \\in loc::tech::carriers_{out}}
            \\frac{\\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{
                carrier\\_ratio(loc::tech::carrier, `out')} =
            -1 * \\sum_{loc::tech::carrier \\in loc::tech::carriers_{in}} (
            \\boldsymbol{carrier_{con}}(loc::tech::carrier, timestep)
            * carrier\\_ratio(loc::tech::carrier, `in') * \\eta_{energy}(loc::tech, timestep))
            \\quad \\forall loc::tech \\in loc::techs_{conversion^{+}}, \\forall timestep \\in timesteps
    """

    carriers_out = backend_model.carrier["out", :, tech].index()
    carriers_in = backend_model.carrier["in", :, tech].index()


# Path: calliope/backend/pyomo/util.py
# @memoize
# def get_param(backend_model, var, dims):
#     """
#     Get an input parameter held in a Pyomo object, or held in the defaults
#     dictionary if that Pyomo object doesn't exist.
# 
#     Parameters
#     ----------
#     backend_model : Pyomo model instance
#     var : str
#     dims : single value or tuple
# 
#     """
#     try:
#         return getattr(backend_model, var)[dims]
#     except AttributeError:  # i.e. parameter doesn't exist at all
#         logger.debug(
#             "get_param: var {} and dims {} leading to default lookup".format(var, dims)
#         )
#         return backend_model.__calliope_defaults[var]
#     except KeyError:  # try removing timestep
#         try:
#             if len(dims) > 2:
#                 return getattr(backend_model, var)[dims[:-1]]
#             else:
#                 return getattr(backend_model, var)[dims[0]]
#         except KeyError:  # Static default value
#             logger.debug(
#                 "get_param: var {} and dims {} leading to default lookup".format(
#                     var, dims
#                 )
#             )
#             return backend_model.__calliope_defaults[var]
# 
# @memoize
# def get_conversion_plus_io(backend_model, tier):
#     """
#     from a carrier_tier, return the primary tier (of `in`, `out`) and
#     corresponding decision variable (`carrier_con` and `carrier_prod`, respectively)
#     """
#     if "out" in tier:
#         return "out", backend_model.carrier_prod
#     elif "in" in tier:
#         return "in", backend_model.carrier_con


# Path: calliope/backend/pyomo/constraints/conversion_plus.py
import pyomo.core as po
from calliope.backend.pyomo.util import (
    get_param,
    get_conversion_plus_io,
)


Conversion plus technology constraints.

"""




def balance_conversion_plus_primary_constraint_rule(
    backend_model, node, tech, timestep
):
    """
    Balance energy carrier consumption and production for carrier_in and carrier_out

    .. container:: scrolling-wrapper

        .. math::

            \\sum_{loc::tech::carrier \\in loc::tech::carriers_{out}}
            \\frac{\\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{
                carrier\\_ratio(loc::tech::carrier, `out')} =
            -1 * \\sum_{loc::tech::carrier \\in loc::tech::carriers_{in}} (
            \\boldsymbol{carrier_{con}}(loc::tech::carrier, timestep)
            * carrier\\_ratio(loc::tech::carrier, `in') * \\eta_{energy}(loc::tech, timestep))
            \\quad \\forall loc::tech \\in loc::techs_{conversion^{+}}, \\forall timestep \\in timesteps
    """

    carriers_out = backend_model.carrier["out", :, tech].index()
    carriers_in = backend_model.carrier["in", :, tech].index()


    energy_eff = get_param(backend_model, "energy_eff", (node, tech, timestep))