示例#1
0
def balance_storage_constraint_rule(backend_model, loc_tech, timestep):
    """
    Balance carrier production and consumption of storage technologies,
    alongside any use of the stored volume.

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{storage}(loc::tech, timestep) =
            \\boldsymbol{storage}(loc::tech, timestep_{previous})
            \\times (1 - storage\\_loss(loc::tech, timestep))^{resolution(timestep)}
            - \\boldsymbol{carrier_{con}}(loc::tech::carrier, timestep)
            \\times \\eta_{energy}(loc::tech, timestep)
            - \\frac{\\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{\\eta_{energy}(loc::tech, timestep)}
            \\quad \\forall loc::tech \\in loc::techs_{storage}, \\forall timestep \\in timesteps
    """
    model_data_dict = backend_model.__calliope_model_data["data"]
    run_config = backend_model.__calliope_run_config

    energy_eff = get_param(backend_model, "energy_eff", (loc_tech, timestep))

    if po.value(energy_eff) == 0:
        carrier_prod = 0
    else:
        loc_tech_carrier = model_data_dict["lookup_loc_techs"][loc_tech]
        carrier_prod = (
            backend_model.carrier_prod[loc_tech_carrier, timestep] /
            energy_eff)

    carrier_con = backend_model.carrier_con[loc_tech_carrier,
                                            timestep] * energy_eff

    current_timestep = backend_model.timesteps.order_dict[timestep]
    if current_timestep == 0 and not run_config["cyclic_storage"]:
        storage_previous_step = (
            get_param(backend_model, "storage_initial", loc_tech) *
            backend_model.storage_cap[loc_tech])
    elif (hasattr(backend_model, "storage_inter_cluster")
          and model_data_dict["lookup_cluster_first_timestep"][timestep]):
        storage_previous_step = 0
    else:
        if (hasattr(backend_model, "clusters") and
                model_data_dict["lookup_cluster_first_timestep"][timestep]):
            previous_step = model_data_dict["lookup_cluster_last_timestep"][
                timestep]
        elif current_timestep == 0 and run_config["cyclic_storage"]:
            previous_step = backend_model.timesteps[-1]
        else:
            previous_step = get_previous_timestep(backend_model.timesteps,
                                                  timestep)
        storage_loss = get_param(backend_model, "storage_loss", loc_tech)
        time_resolution = backend_model.timestep_resolution[previous_step]
        storage_previous_step = (
            (1 - storage_loss)**
            time_resolution) * backend_model.storage[loc_tech, previous_step]

    return (backend_model.storage[loc_tech,
                                  timestep] == storage_previous_step -
            carrier_prod - carrier_con)
示例#2
0
def ramping_constraint(backend_model, loc_tech_carrier, timestep, direction=0):
    """
    Ramping rate constraints.

    Direction: 0 is up, 1 is down.

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{max\\_ramping\\_rate}(loc::tech::carrier, timestep) =
            energy_{ramping}(loc::tech, timestep) \\times energy_{cap}(loc::tech)

            \\boldsymbol{diff}(loc::tech::carrier, timestep) =
            (carrier_{prod}(loc::tech::carrier, timestep) + carrier_{con}(loc::tech::carrier, timestep))
            / timestep\\_resolution(timestep) -
            (carrier_{prod}(loc::tech::carrier, timestep-1) + carrier_{con}(loc::tech::carrier, timestep-1))
            / timestep\\_resolution(timestep-1)

    """

    # No constraint for first timestep
    # Pyomo returns the order 1-indexed, but we want 0-indexing
    if backend_model.timesteps.ord(timestep) - 1 == 0:
        return po.Constraint.NoConstraint
    else:
        previous_step = get_previous_timestep(backend_model.timesteps,
                                              timestep)
        time_res = backend_model.timestep_resolution[timestep]
        time_res_prev = backend_model.timestep_resolution[previous_step]
        loc_tech = loc_tech_carrier.rsplit("::", 1)[0]
        # Ramping rate (fraction of installed capacity per hour)
        ramping_rate = get_param(backend_model, "energy_ramping",
                                 (loc_tech, timestep))

        try:
            prod_this = backend_model.carrier_prod[loc_tech_carrier, timestep]
            prod_prev = backend_model.carrier_prod[loc_tech_carrier,
                                                   previous_step]
        except KeyError:
            prod_this = 0
            prod_prev = 0

        try:
            con_this = backend_model.carrier_con[loc_tech_carrier, timestep]
            con_prev = backend_model.carrier_con[loc_tech_carrier,
                                                 previous_step]
        except KeyError:
            con_this = 0
            con_prev = 0

        diff = (prod_this + con_this) / time_res - (prod_prev +
                                                    con_prev) / time_res_prev

        max_ramping_rate = ramping_rate * backend_model.energy_cap[loc_tech]

        if direction == 0:
            return diff <= max_ramping_rate
        else:
            return -1 * max_ramping_rate <= diff
示例#3
0
def ramping_constraint(backend_model, loc_tech_carrier, timestep, direction=0):
    """
    Ramping rate constraints.

    Direction: 0 is up, 1 is down.

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{max\\_ramping\\_rate}(loc::tech::carrier, timestep) =
            energy_{ramping}(loc::tech, timestep) \\times energy_{cap}(loc::tech)

            \\boldsymbol{diff}(loc::tech::carrier, timestep) =
            (carrier_{prod}(loc::tech::carrier, timestep) + carrier_{con}(loc::tech::carrier, timestep))
            / timestep\\_resolution(timestep) -
            (carrier_{prod}(loc::tech::carrier, timestep-1) + carrier_{con}(loc::tech::carrier, timestep-1))
            / timestep\\_resolution(timestep-1)

    """

    # No constraint for first timestep
    if backend_model.timesteps.order_dict[timestep] == 0:
        return po.Constraint.NoConstraint
    else:
        previous_step = get_previous_timestep(backend_model.timesteps, timestep)
        time_res = backend_model.timestep_resolution[timestep]
        time_res_prev = backend_model.timestep_resolution[previous_step]
        loc_tech = loc_tech_carrier.rsplit('::', 1)[0]
        # Ramping rate (fraction of installed capacity per hour)
        ramping_rate = get_param(backend_model, 'energy_ramping', (loc_tech, timestep))

        try:
            prod_this = backend_model.carrier_prod[loc_tech_carrier, timestep]
            prod_prev = backend_model.carrier_prod[loc_tech_carrier, previous_step]
        except KeyError:
            prod_this = 0
            prod_prev = 0

        try:
            con_this = backend_model.carrier_con[loc_tech_carrier, timestep]
            con_prev = backend_model.carrier_con[loc_tech_carrier, previous_step]
        except KeyError:
            con_this = 0
            con_prev = 0

        diff = (
            (prod_this + con_this) / time_res -
            (prod_prev + con_prev) / time_res_prev
        )

        max_ramping_rate = ramping_rate * backend_model.energy_cap[loc_tech]

        if direction == 0:
            return diff <= max_ramping_rate
        else:
            return -1 * max_ramping_rate <= diff
示例#4
0
def balance_storage_constraint_rule(backend_model, loc_tech, timestep):
    """
    Balance carrier production and consumption of storage technologies,
    alongside any use of the stored volume.

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{storage}(loc::tech, timestep) =
            \\boldsymbol{storage}(loc::tech, timestep_{previous})
            \\times (1 - storage\\_loss(loc::tech, timestep))^{resolution(timestep)}
            - \\boldsymbol{carrier_{con}}(loc::tech::carrier, timestep)
            \\times \\eta_{energy}(loc::tech, timestep)
            - \\frac{\\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{\\eta_{energy}(loc::tech, timestep)}
            \\quad \\forall loc::tech \\in loc::techs_{storage}, \\forall timestep \\in timesteps
    """
    model_data_dict = backend_model.__calliope_model_data__['data']
    model_attrs = backend_model.__calliope_model_data__['attrs']

    energy_eff = get_param(backend_model, 'energy_eff', (loc_tech, timestep))

    if po.value(energy_eff) == 0:
        carrier_prod = 0
    else:
        loc_tech_carrier = model_data_dict['lookup_loc_techs'][loc_tech]
        carrier_prod = backend_model.carrier_prod[loc_tech_carrier, timestep] / energy_eff

    carrier_con = backend_model.carrier_con[loc_tech_carrier, timestep] * energy_eff

    current_timestep = backend_model.timesteps.order_dict[timestep]
    if current_timestep == 0 and not model_attrs['run.cyclic_storage']:
        storage_previous_step = get_param(backend_model, 'storage_initial', loc_tech)
    elif (hasattr(backend_model, 'storage_inter_cluster') and
            model_data_dict['lookup_cluster_first_timestep'][timestep]):
        storage_previous_step = 0
    else:
        if (hasattr(backend_model, 'clusters') and
                model_data_dict['lookup_cluster_first_timestep'][timestep]):
            previous_step = model_data_dict['lookup_cluster_last_timestep'][timestep]
        elif current_timestep == 0 and model_attrs['run.cyclic_storage']:
            previous_step = backend_model.timesteps[-1]
        else:
            previous_step = get_previous_timestep(backend_model.timesteps, timestep)
        storage_loss = get_param(backend_model, 'storage_loss', loc_tech)
        time_resolution = backend_model.timestep_resolution[previous_step]
        storage_previous_step = (
            ((1 - storage_loss) ** time_resolution) *
            backend_model.storage[loc_tech, previous_step]
        )

    return (
        backend_model.storage[loc_tech, timestep] ==
        storage_previous_step - carrier_prod - carrier_con
    )
示例#5
0
def balance_storage_inter_cluster_rule(backend_model, loc_tech, datestep):
    """
    When clustering days, to reduce the timeseries length, balance the daily stored
    energy across all days of the original timeseries.

    `Ref: DOI 10.1016/j.apenergy.2018.01.023 <https://doi.org/10.1016/j.apenergy.2018.01.023>`_

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{storage_{inter\\_cluster}}(loc::tech, datestep) =
            \\boldsymbol{storage_{inter\\_cluster}}(loc::tech, datestep_{previous})
            \\times (1 - storage\\_loss(loc::tech, timestep))^{24}
            + \\boldsymbol{storage}(loc::tech, timestep_{final, cluster(datestep))})
            \\quad \\forall loc::tech \\in loc::techs_{store}, \\forall datestep \\in datesteps

    Where :math:`timestep_{final, cluster(datestep_{previous}))}` is the final timestep of the
    cluster in the clustered timeseries corresponding to the previous day
    """
    model_attrs = backend_model.__calliope_model_data__['attrs']
    current_datestep = backend_model.datesteps.order_dict[datestep]

    if current_datestep == 0 and not model_attrs['run.cyclic_storage']:
        storage_previous_step = get_param(backend_model, 'storage_initial', loc_tech)
        storage_intra = 0
    else:
        if current_datestep == 0 and model_attrs['run.cyclic_storage']:
            previous_step = backend_model.datesteps[-1]
        else:
            previous_step = get_previous_timestep(backend_model.datesteps, datestep)
        storage_loss = get_param(backend_model, 'storage_loss', loc_tech)
        storage_previous_step = (
            ((1 - storage_loss) ** 24) *
            backend_model.storage_inter_cluster[loc_tech, previous_step]
        )
        final_timestep = (
            backend_model.__calliope_model_data__
            ['data']['lookup_datestep_last_cluster_timestep'][previous_step]
        )
        storage_intra = backend_model.storage[loc_tech, final_timestep]
    return (
        backend_model.storage_inter_cluster[loc_tech, datestep] ==
        storage_previous_step + storage_intra
    )
示例#6
0
def balance_storage_constraint_rule(backend_model, loc_tech, timestep):
    """
    Balance carrier production and consumption of storage technologies,
    alongside any use of the stored volume.

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{storage}(loc::tech, timestep) =
            \\boldsymbol{storage}(loc::tech, timestep_{previous})
            \\times (1 - storage\_loss(loc::tech, timestep))^{resolution(timestep)}
            - \\boldsymbol{carrier_{con}}(loc::tech::carrier, timestep)
            \\times \\eta_{energy}(loc::tech, timestep)
            - \\frac{\\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{\\eta_{energy}(loc::tech, timestep)}
            \\quad \\forall loc::tech \\in loc::techs_{storage}, \\forall timestep \\in timesteps
    """
    model_data_dict = backend_model.__calliope_model_data__['data']

    energy_eff = get_param(backend_model, 'energy_eff', (loc_tech, timestep))

    if po.value(energy_eff) == 0:
        carrier_prod = 0
    else:
        loc_tech_carrier = model_data_dict['lookup_loc_techs'][loc_tech]
        carrier_prod = backend_model.carrier_prod[loc_tech_carrier, timestep] / energy_eff

    carrier_con = backend_model.carrier_con[loc_tech_carrier, timestep] * energy_eff

    if backend_model.timesteps.order_dict[timestep] == 0:
        storage_previous_step = get_param(backend_model, 'storage_initial', loc_tech)
    else:
        storage_loss = get_param(backend_model, 'storage_loss', loc_tech)
        previous_step = get_previous_timestep(backend_model, timestep)
        time_resolution = backend_model.timestep_resolution[previous_step]
        storage_previous_step = (
            ((1 - storage_loss) ** time_resolution) *
            backend_model.storage[loc_tech, previous_step]
        )

    return (
        backend_model.storage[loc_tech, timestep] ==
        storage_previous_step - carrier_prod - carrier_con
    )
示例#7
0
def _ramping_constraint_rule(backend_model, loc_tech_carrier, timestep, direction=0):
    """
    Ramping rate constraints.

    Direction: 0 is up, 1 is down.

    """

    # No constraint for first timestep
    if backend_model.timesteps.order_dict[timestep] == 0:
        return po.Constraint.NoConstraint
    else:
        previous_step = get_previous_timestep(backend_model, timestep)
        time_res = backend_model.timestep_resolution[timestep]
        time_res_prev = backend_model.timestep_resolution[previous_step]
        loc_tech = loc_tech_carrier.rsplit('::', 1)[0]
        # Ramping rate (fraction of installed capacity per hour)
        ramping_rate = get_param(backend_model, 'energy_ramping', (loc_tech, timestep))

        try:
            prod_this = backend_model.carrier_prod[loc_tech_carrier, timestep]
            prod_prev = backend_model.carrier_prod[loc_tech_carrier, previous_step]
        except KeyError:
            prod_this = 0
            prod_prev = 0

        try:
            con_this = backend_model.carrier_con[loc_tech_carrier, timestep]
            con_prev = backend_model.carrier_con[loc_tech_carrier, previous_step]
        except KeyError:
            con_this = 0
            con_prev = 0

        diff = (
            (prod_this + con_this) / time_res -
            (prod_prev + con_prev) / time_res_prev
        )

        max_ramping_rate = ramping_rate * backend_model.energy_cap[loc_tech]

        if direction == 0:
            return diff <= max_ramping_rate
        else:
            return -1 * max_ramping_rate <= diff
示例#8
0
def balance_storage_inter_constraint_rule(backend_model, node, tech, datestep):
    """
    When clustering days, to reduce the timeseries length, balance the daily stored
    energy across all days of the original timeseries.

    `Ref: DOI 10.1016/j.apenergy.2018.01.023 <https://doi.org/10.1016/j.apenergy.2018.01.023>`_

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{storage_{inter\\_cluster}}(loc::tech, datestep) =
            \\boldsymbol{storage_{inter\\_cluster}}(loc::tech, datestep_{previous})
            \\times (1 - storage\\_loss(loc::tech, timestep))^{24}
            + \\boldsymbol{storage}(loc::tech, timestep_{final, cluster(datestep))})
            \\quad \\forall loc::tech \\in loc::techs_{store}, \\forall datestep \\in datesteps

    Where :math:`timestep_{final, cluster(datestep_{previous}))}` is the final timestep of the
    cluster in the clustered timeseries corresponding to the previous day
    """
    run_config = backend_model.__calliope_run_config
    # Pyomo returns the order 1-indexed, but we want 0-indexing
    current_datestep = backend_model.datesteps.ord(datestep) - 1

    if current_datestep == 0 and not run_config["cyclic_storage"]:
        storage_previous_step = get_param(backend_model, "storage_initial",
                                          (node, tech))
        storage_intra = 0
    else:
        if current_datestep == 0 and run_config["cyclic_storage"]:
            previous_step = backend_model.datesteps[-1]
        else:
            previous_step = get_previous_timestep(backend_model.datesteps,
                                                  datestep)
        storage_loss = get_param(backend_model, "storage_loss", (node, tech))
        storage_previous_step = (
            (1 - storage_loss)**
            24) * backend_model.storage_inter_cluster[node, tech,
                                                      previous_step]
        final_timestep = backend_model.lookup_datestep_last_cluster_timestep[
            previous_step].value
        storage_intra = backend_model.storage[node, tech, final_timestep]
    return (backend_model.storage_inter_cluster[node, tech, datestep] ==
            storage_previous_step + storage_intra)
示例#9
0
def balance_storage_inter_cluster_rule(backend_model, loc_tech, datestep):
    """
    When clustering days, to reduce the timeseries length, balance the daily stored
    energy across all days of the original timeseries.

    `Ref: DOI 10.1016/j.apenergy.2018.01.023 <https://doi.org/10.1016/j.apenergy.2018.01.023>`_

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{storage_{inter\_cluster}}(loc::tech, datestep) =
            \\boldsymbol{storage_{inter\_cluster}}(loc::tech, datestep_{previous})
            \\times (1 - storage\_loss(loc::tech, timestep))^{24}
            + \\boldsymbol{storage}(loc::tech, timestep_{final, cluster(datestep))})
            \\quad \\forall loc::tech \\in loc::techs_{store}, \\forall datestep \\in datesteps

    Where :math:`timestep_{final, cluster(datestep_{previous}))}` is the final timestep of the
    cluster in the clustered timeseries corresponding to the previous day
    """
    model_attrs = backend_model.__calliope_model_data__['attrs']
    current_datestep = backend_model.datesteps.order_dict[datestep]

    if current_datestep == 0 and not model_attrs['run.cyclic_storage']:
        storage_previous_step = get_param(backend_model, 'storage_initial',
                                          loc_tech)
        storage_intra = 0
    else:
        if current_datestep == 0 and model_attrs['run.cyclic_storage']:
            previous_step = backend_model.datesteps[-1]
        else:
            previous_step = get_previous_timestep(backend_model.datesteps,
                                                  datestep)
        storage_loss = get_param(backend_model, 'storage_loss', loc_tech)
        storage_previous_step = (
            ((1 - storage_loss)**24) *
            backend_model.storage_inter_cluster[loc_tech, previous_step])
        final_timestep = (
            backend_model.__calliope_model_data__['data']
            ['lookup_datestep_last_cluster_timestep'][previous_step])
        storage_intra = backend_model.storage[loc_tech, final_timestep]
    return (backend_model.storage_inter_cluster[loc_tech, datestep] ==
            storage_previous_step + storage_intra)
示例#10
0
def balance_supply_plus_constraint_rule(backend_model, loc_tech, timestep):
    """
    Balance carrier production and resource consumption of supply_plus technologies
    alongside any use of resource storage.

    .. _system_balance_constraint:

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{storage}(loc::tech, timestep) =
            \\boldsymbol{storage}(loc::tech, timestep_{previous})
            \\times (1 - storage\\_loss(loc::tech, timestep))^{timestep\\_resolution(timestep)} +
            \\boldsymbol{resource_{con}}(loc::tech, timestep) \\times \\eta_{resource}(loc::tech, timestep) -
            \\frac{\\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{\\eta_{energy}(loc::tech, timestep) \\times \\eta_{parasitic}(loc::tech, timestep)}
            \\quad \\forall loc::tech \\in loc::techs_{supply^{+}}, \\forall timestep \\in timesteps

    If *no* storage is defined for the technology, this reduces to:

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{resource_{con}}(loc::tech, timestep) \\times \\eta_{resource}(loc::tech, timestep) =
            \\frac{\\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{\\eta_{energy}(loc::tech, timestep) \\times \\eta_{parasitic}(loc::tech, timestep)}
            \\quad \\forall loc::tech \\in loc::techs_{supply^{+}}, \\forall timestep \\in timesteps

    """

    model_data_dict = backend_model.__calliope_model_data["data"]
    run_config = backend_model.__calliope_run_config

    resource_eff = get_param(backend_model, "resource_eff",
                             (loc_tech, timestep))
    energy_eff = get_param(backend_model, "energy_eff", (loc_tech, timestep))
    parasitic_eff = get_param(backend_model, "parasitic_eff",
                              (loc_tech, timestep))
    total_eff = energy_eff * parasitic_eff

    if po.value(total_eff) == 0:
        carrier_prod = 0
    else:
        loc_tech_carrier = model_data_dict["lookup_loc_techs"][loc_tech]
        carrier_prod = (
            backend_model.carrier_prod[loc_tech_carrier, timestep] / total_eff)

    # A) Case where no storage allowed
    if not loc_tech_is_in(backend_model, loc_tech, "loc_techs_store"):
        return (backend_model.resource_con[loc_tech, timestep] *
                resource_eff == carrier_prod)

    # B) Case where storage is allowed
    else:
        resource = backend_model.resource_con[loc_tech,
                                              timestep] * resource_eff
        current_timestep = backend_model.timesteps.order_dict[timestep]
        if current_timestep == 0 and not run_config["cyclic_storage"]:
            storage_previous_step = (
                get_param(backend_model, "storage_initial", loc_tech) *
                backend_model.storage_cap[loc_tech])
        elif (hasattr(backend_model, "storage_inter_cluster")
              and model_data_dict["lookup_cluster_first_timestep"][timestep]):
            storage_previous_step = 0
        else:
            if (hasattr(backend_model, "clusters") and
                    model_data_dict["lookup_cluster_first_timestep"][timestep]
                ):
                previous_step = model_data_dict[
                    "lookup_cluster_last_timestep"][timestep]
            elif current_timestep == 0 and run_config["cyclic_storage"]:
                previous_step = backend_model.timesteps[-1]
            else:
                previous_step = get_previous_timestep(backend_model.timesteps,
                                                      timestep)
            storage_loss = get_param(backend_model, "storage_loss", loc_tech)
            time_resolution = backend_model.timestep_resolution[previous_step]
            storage_previous_step = (
                (1 - storage_loss)**
                time_resolution) * backend_model.storage[loc_tech,
                                                         previous_step]

        return (backend_model.storage[loc_tech,
                                      timestep] == storage_previous_step +
                resource - carrier_prod)
示例#11
0
def balance_supply_plus_constraint_rule(backend_model, loc_tech, timestep):
    """
    Balance carrier production and resource consumption of supply_plus technologies
    alongside any use of resource storage.

    .. _system_balance_constraint:

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{storage}(loc::tech, timestep) =
            \\boldsymbol{storage}(loc::tech, timestep_{previous})
            \\times (1 - storage\_loss(loc::tech, timestep))^{timestep\_resolution(timestep)} +
            \\boldsymbol{resource_{con}}(loc::tech, timestep) -
            \\frac{\\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{\\eta_{energy}(loc::tech, timestep) \\times \\eta_{parasitic}(loc::tech, timestep)}
            \\quad \\forall loc::tech \\in loc::techs_{supply^{+}}, \\forall timestep \\in timesteps

    If *no* storage is defined for the technology, this reduces to:

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{resource_{con}}(loc::tech, timestep) =
            \\frac{\\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{\\eta_{energy}(loc::tech, timestep) \\times \\eta_{parasitic}(loc::tech, timestep)}
            \\quad \\forall loc::tech \\in loc::techs_{supply^{+}}, \\forall timestep \\in timesteps

    """

    model_data_dict = backend_model.__calliope_model_data__['data']

    energy_eff = get_param(backend_model, 'energy_eff', (loc_tech, timestep))
    parasitic_eff = get_param(backend_model, 'parasitic_eff', (loc_tech, timestep))
    total_eff = energy_eff * parasitic_eff

    if po.value(total_eff) == 0:
        carrier_prod = 0
    else:
        loc_tech_carrier = model_data_dict['lookup_loc_techs'][loc_tech]
        carrier_prod = backend_model.carrier_prod[loc_tech_carrier, timestep] / total_eff

    # A) Case where no storage allowed
    if not loc_tech_is_in(backend_model, loc_tech, 'loc_techs_store'):
        return backend_model.resource_con[loc_tech, timestep] == carrier_prod

    # B) Case where storage is allowed
    else:
        resource = backend_model.resource_con[loc_tech, timestep]
        if backend_model.timesteps.order_dict[timestep] == 0:
            storage_previous_step = get_param(backend_model, 'storage_initial', loc_tech)
        else:
            storage_loss = get_param(backend_model, 'storage_loss', loc_tech)
            previous_step = get_previous_timestep(backend_model, timestep)
            time_resolution = backend_model.timestep_resolution[previous_step]
            storage_previous_step = (
                ((1 - storage_loss) ** time_resolution) *
                backend_model.storage[loc_tech, previous_step]
            )

        return (
            backend_model.storage[loc_tech, timestep] ==
            storage_previous_step + resource - carrier_prod
        )
示例#12
0
def balance_supply_plus_constraint_rule(backend_model, loc_tech, timestep):
    """
    Balance carrier production and resource consumption of supply_plus technologies
    alongside any use of resource storage.

    .. _system_balance_constraint:

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{storage}(loc::tech, timestep) =
            \\boldsymbol{storage}(loc::tech, timestep_{previous})
            \\times (1 - storage\\_loss(loc::tech, timestep))^{timestep\\_resolution(timestep)} +
            \\boldsymbol{resource_{con}}(loc::tech, timestep) \\times \\eta_{resource}(loc::tech, timestep) -
            \\frac{\\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{\\eta_{energy}(loc::tech, timestep) \\times \\eta_{parasitic}(loc::tech, timestep)}
            \\quad \\forall loc::tech \\in loc::techs_{supply^{+}}, \\forall timestep \\in timesteps

    If *no* storage is defined for the technology, this reduces to:

    .. container:: scrolling-wrapper

        .. math::

            \\boldsymbol{resource_{con}}(loc::tech, timestep) \\times \\eta_{resource}(loc::tech, timestep) =
            \\frac{\\boldsymbol{carrier_{prod}}(loc::tech::carrier, timestep)}{\\eta_{energy}(loc::tech, timestep) \\times \\eta_{parasitic}(loc::tech, timestep)}
            \\quad \\forall loc::tech \\in loc::techs_{supply^{+}}, \\forall timestep \\in timesteps

    """

    model_data_dict = backend_model.__calliope_model_data__['data']
    model_attrs = backend_model.__calliope_model_data__['attrs']

    resource_eff = get_param(backend_model, 'resource_eff', (loc_tech, timestep))
    energy_eff = get_param(backend_model, 'energy_eff', (loc_tech, timestep))
    parasitic_eff = get_param(backend_model, 'parasitic_eff', (loc_tech, timestep))
    total_eff = energy_eff * parasitic_eff

    if po.value(total_eff) == 0:
        carrier_prod = 0
    else:
        loc_tech_carrier = model_data_dict['lookup_loc_techs'][loc_tech]
        carrier_prod = backend_model.carrier_prod[loc_tech_carrier, timestep] / total_eff

    # A) Case where no storage allowed
    if not loc_tech_is_in(backend_model, loc_tech, 'loc_techs_store'):
        return backend_model.resource_con[loc_tech, timestep] * resource_eff == carrier_prod

    # B) Case where storage is allowed
    else:
        resource = backend_model.resource_con[loc_tech, timestep] * resource_eff
        current_timestep = backend_model.timesteps.order_dict[timestep]
        if current_timestep == 0 and not model_attrs['run.cyclic_storage']:
            storage_previous_step = get_param(backend_model, 'storage_initial', loc_tech)
        elif (hasattr(backend_model, 'storage_inter_cluster') and
                model_data_dict['lookup_cluster_first_timestep'][timestep]):
            storage_previous_step = 0
        else:
            if (hasattr(backend_model, 'clusters') and
                    model_data_dict['lookup_cluster_first_timestep'][timestep]):
                previous_step = model_data_dict['lookup_cluster_last_timestep'][timestep]
            elif current_timestep == 0 and model_attrs['run.cyclic_storage']:
                previous_step = backend_model.timesteps[-1]
            else:
                previous_step = get_previous_timestep(backend_model.timesteps, timestep)
            storage_loss = get_param(backend_model, 'storage_loss', loc_tech)
            time_resolution = backend_model.timestep_resolution[previous_step]
            storage_previous_step = (
                ((1 - storage_loss) ** time_resolution) *
                backend_model.storage[loc_tech, previous_step]
            )

        return (
            backend_model.storage[loc_tech, timestep] ==
            storage_previous_step + resource - carrier_prod
        )