コード例 #1
0
ファイル: dr.py プロジェクト: yangqiu91/gridpath
def power_delta_rule(mod, p, tmp):
    """
    This rule is only used in tuning costs, so fine to skip for linked
    horizon's first timepoint.
    """
    if check_if_first_timepoint(
            mod=mod, tmp=tmp, balancing_type=mod.balancing_type_project[p]
    ) and (check_boundary_type(mod=mod,
                               tmp=tmp,
                               balancing_type=mod.balancing_type_project[p],
                               boundary_type="linear")
           or check_boundary_type(mod=mod,
                                  tmp=tmp,
                                  balancing_type=mod.balancing_type_project[p],
                                  boundary_type="linked")):
        pass
    else:
        return (mod.DR_Shift_Up_MW[p, tmp]
                - mod.DR_Shift_Down_MW[p, tmp]) - \
            (mod.DR_Shift_Up_MW[
                 p, mod.prev_tmp[tmp, mod.balancing_type_project[p]]
             ]
                - mod.DR_Shift_Down_MW[
                 p, mod.prev_tmp[tmp, mod.balancing_type_project[p]]
             ])
コード例 #2
0
def energy_tracking_rule(mod, s, tmp):
    """
    **Constraint Name**: GenVarStorHyb_Energy_Tracking_Constraint
    **Enforced Over**: GEN_VAR_STOR_HYB_OPR_TMPS

    The energy stored in each timepoint is equal to the energy stored in the
    previous timepoint minus any discharged power (adjusted for discharging
    efficiency and timepoint duration) plus any charged power (adjusted for
    charging efficiency and timepoint duration).
    """
    if check_if_first_timepoint(
        mod=mod, tmp=tmp, balancing_type=mod.balancing_type_project[s]
    ) and check_boundary_type(
        mod=mod,
        tmp=tmp,
        balancing_type=mod.balancing_type_project[s],
        boundary_type="linear",
    ):
        return Constraint.Skip
    else:
        if check_if_first_timepoint(
            mod=mod, tmp=tmp, balancing_type=mod.balancing_type_project[s]
        ) and check_boundary_type(
            mod=mod,
            tmp=tmp,
            balancing_type=mod.balancing_type_project[s],
            boundary_type="linked",
        ):
            prev_tmp_hrs_in_tmp = mod.hrs_in_linked_tmp[0]
            prev_tmp_starting_energy_in_storage = (
                mod.gen_var_stor_hyb_linked_starting_energy_in_storage[s, 0]
            )
            prev_tmp_discharge = mod.gen_var_stor_hyb_linked_discharge[s, 0]
            prev_tmp_charge = mod.gen_var_stor_hyb_linked_charge[s, 0]
        else:
            prev_tmp_hrs_in_tmp = mod.hrs_in_tmp[
                mod.prev_tmp[tmp, mod.balancing_type_project[s]]
            ]
            prev_tmp_starting_energy_in_storage = (
                mod.GenVarStorHyb_Starting_Energy_in_Storage_MWh[
                    s, mod.prev_tmp[tmp, mod.balancing_type_project[s]]
                ]
            )
            prev_tmp_discharge = mod.GenVarStorHyb_Discharge_MW[
                s, mod.prev_tmp[tmp, mod.balancing_type_project[s]]
            ]
            prev_tmp_charge = mod.GenVarStorHyb_Charge_MW[
                s, mod.prev_tmp[tmp, mod.balancing_type_project[s]]
            ]

        return (
            mod.GenVarStorHyb_Starting_Energy_in_Storage_MWh[s, tmp]
            == prev_tmp_starting_energy_in_storage
            + prev_tmp_charge
            * prev_tmp_hrs_in_tmp
            * mod.gen_var_stor_hyb_charging_efficiency[s]
            - prev_tmp_discharge
            * prev_tmp_hrs_in_tmp
            / mod.gen_var_stor_hyb_discharging_efficiency[s]
        )
コード例 #3
0
ファイル: stor.py プロジェクト: rachceew/gridpath
def power_delta_rule(mod, g, tmp):
    """
    This rule is only used in tuning costs, so fine to skip for linked
    horizon's first timepoint.
    """
    if check_if_first_timepoint(
        mod=mod, tmp=tmp, balancing_type=mod.balancing_type_project[g]
    ) and (
        check_boundary_type(
            mod=mod, tmp=tmp,
            balancing_type=mod.balancing_type_project[g],
            boundary_type="linear"
        ) or
        check_boundary_type(
            mod=mod, tmp=tmp,
            balancing_type=mod.balancing_type_project[g],
            boundary_type="linked"
        )
    ):
        pass
    else:
        return (mod.Stor_Discharge_MW[g, tmp] -
                mod.Stor_Charge_MW[g, tmp]) \
            - (mod.Stor_Discharge_MW[g, mod.prev_tmp[
                tmp, mod.balancing_type_project[g]]]
               - mod.Stor_Charge_MW[g, mod.prev_tmp[
                tmp, mod.balancing_type_project[g]]])
コード例 #4
0
ファイル: gen_var.py プロジェクト: yangqiu91/gridpath
def power_delta_rule(mod, g, tmp):
    """
    Curtailment is counted as part of the ramp here; excludes any ramping from
    reserve provision.

    This rule is only used in tuning costs, so fine to skip for linked
    horizon's first timepoint.
    """
    if check_if_first_timepoint(
        mod=mod, tmp=tmp, balancing_type=mod.balancing_type_project[g]
    ) and (
        check_boundary_type(
            mod=mod, tmp=tmp,
            balancing_type=mod.balancing_type_project[g],
            boundary_type="linear"
        ) or
        check_boundary_type(
            mod=mod, tmp=tmp,
            balancing_type=mod.balancing_type_project[g],
            boundary_type="linked"
        )
    ):
        pass
    else:
        return \
            (mod.Capacity_MW[g, mod.period[tmp]]
             * mod.Availability_Derate[g, tmp]
             * mod.gen_var_cap_factor[g, tmp]) \
            - (mod.Capacity_MW[g, mod.period[mod.prev_tmp[
                tmp, mod.balancing_type_project[g]]]]
               * mod.Availability_Derate[g, mod.prev_tmp[
                tmp, mod.balancing_type_project[g]]]
               * mod.gen_var_cap_factor[g, mod.prev_tmp[
                tmp, mod.balancing_type_project[g]]])
コード例 #5
0
def power_delta_rule(mod, g, tmp):
    """
    Exogenously defined ramp for variable must-take generators.

    This rule is only used in tuning costs, so fine to skip for linked
    horizon's first timepoint.
    """
    if check_if_first_timepoint(
            mod=mod, tmp=tmp, balancing_type=mod.balancing_type_project[g]
    ) and (check_boundary_type(mod=mod,
                               tmp=tmp,
                               balancing_type=mod.balancing_type_project[g],
                               boundary_type="linear")
           or check_boundary_type(mod=mod,
                                  tmp=tmp,
                                  balancing_type=mod.balancing_type_project[g],
                                  boundary_type="linked")):
        pass
    else:
        return \
            (mod.Capacity_MW[g, mod.period[tmp]]
             * mod.Availability_Derate[g, tmp]
             * mod.gen_var_must_take_cap_factor[g, tmp]) \
            - (mod.Capacity_MW[g, mod.period[mod.prev_tmp[
                    tmp, mod.balancing_type_project[g]]]]
               * mod.Availability_Derate[g, mod.prev_tmp[
                    tmp, mod.balancing_type_project[g]]]
               * mod.gen_var_must_take_cap_factor[g, mod.prev_tmp[
                    tmp, mod.balancing_type_project[g]]])
コード例 #6
0
ファイル: stor.py プロジェクト: rachceew/gridpath
def energy_tracking_rule(mod, s, tmp):
    """
    **Constraint Name**: Stor_Energy_Tracking_Constraint
    **Enforced Over**: STOR_OPR_TMPS

    The energy stored in each timepoint is equal to the energy stored in the
    previous timepoint minus any discharged power (adjusted for discharging
    efficiency and timepoint duration) plus any charged power (adjusted for
    charging efficiency and timepoint duration).
    """
    if check_if_first_timepoint(
            mod=mod, tmp=tmp, balancing_type=mod.balancing_type_project[s]
    ) and check_boundary_type(
        mod=mod, tmp=tmp, balancing_type=mod.balancing_type_project[s],
        boundary_type="linear"
    ):
        return Constraint.Skip
    else:
        if check_if_first_timepoint(
            mod=mod, tmp=tmp, balancing_type=mod.balancing_type_project[s]
        ) and check_boundary_type(
            mod=mod, tmp=tmp, balancing_type=mod.balancing_type_project[s],
            boundary_type="linked"
        ):
            prev_tmp_hrs_in_tmp = mod.hrs_in_linked_tmp[0]
            prev_tmp_starting_energy_in_storage = \
                mod.stor_linked_starting_energy_in_storage[s, 0]
            prev_tmp_discharge = mod.stor_linked_discharge[s, 0]
            prev_tmp_charge = mod.stor_linked_charge[s, 0]
        else:
            prev_tmp_hrs_in_tmp = mod.hrs_in_tmp[
                mod.prev_tmp[tmp, mod.balancing_type_project[s]]
            ]
            prev_tmp_starting_energy_in_storage = \
                mod.Stor_Starting_Energy_in_Storage_MWh[
                    s, mod.prev_tmp[tmp, mod.balancing_type_project[s]]
                ]
            prev_tmp_discharge = \
                mod.Stor_Discharge_MW[
                    s, mod.prev_tmp[tmp, mod.balancing_type_project[s]]
                ]
            prev_tmp_charge = \
                mod.Stor_Charge_MW[
                    s, mod.prev_tmp[tmp, mod.balancing_type_project[s]]
                ]

        return \
            mod.Stor_Starting_Energy_in_Storage_MWh[s, tmp] \
            == prev_tmp_starting_energy_in_storage \
            + prev_tmp_charge * prev_tmp_hrs_in_tmp \
            * mod.stor_charging_efficiency[s] \
            - prev_tmp_discharge * prev_tmp_hrs_in_tmp \
            / mod.stor_discharging_efficiency[s]
コード例 #7
0
def power_delta_rule(mod, g, tmp):
    """
    This rule is only used in tuning costs, so fine to skip for linked
    horizon's first timepoint.
    """
    if check_if_first_timepoint(
            mod=mod, tmp=tmp, balancing_type=mod.balancing_type_project[g]
    ) and (check_boundary_type(mod=mod,
                               tmp=tmp,
                               balancing_type=mod.balancing_type_project[g],
                               boundary_type="linear")
           or check_boundary_type(mod=mod,
                                  tmp=tmp,
                                  balancing_type=mod.balancing_type_project[g],
                                  boundary_type="linked")):
        pass
    else:
        return mod.GenHydroMustTake_Gross_Power_MW[g, tmp] \
            - mod.GenHydroMustTake_Gross_Power_MW[g, mod.prev_tmp[
                tmp, mod.balancing_type_project[g]]]
コード例 #8
0
def determine_relevant_timepoints(mod, g, tmp, min_time):
    """
    :param mod:
    :param g:
    :param tmp:
    :param min_time:
    :return: the relevant timepoints to look at for the minimum up/down time
        constraints

    We need to figure out how far back we need to look,
    i.e. which timepoints we need to consider when capacity could have
    been turned on/off that must still be on/off in the current timepoint *t*.

    Any capacity that was turned on/off between t and t-1 must still be
    on/off in t, so timepoint *t* is a relevant timepoint.

    Capacity must also still be on/off if it was turned on/off less than its
    up/down time ago, i.e. if it was turned on/off between timepoints that
    are within the min up/down time from the beginning of the current
    timepoint. Once we reach a timepoint whose duration takes us to a
    point in time that is removed from the beginning of timepoint *t* by a
    time greater than or equal to the min_time, that timepoint is not
    relevant anymore and we have completed our list of relevant timepoints.

    In a simple case, let's assume all timepoints have durations of 1 hour.
    Timepoint t-1 is removed from the start of timepoint *t* by an hour,
    timepoint t-2 by 2 hours, timepoint t-3 by 3 hours, etc. Therefore, if
    if a generator has a 4-hour minimum up time and was started up in t-3 (
    i.e. between t-4 and t-3), then it must still be on in the current
    timepoint. If it was started up in t-4, it has already been up for 4
    hours by the time timepoint *t* begins, so it can be turned off. The
    relevant timepoints are therefore t-1, t-2, and t-3; we do not need to
    constrain capacity turned on/off in t-4 or farther in the past.

    If t-2 has duration of 2-hours, on the other hand, the total duration of
    the previous three timepoints would be 4 hours and the generator turned
    on in t-3 should therefore be allowed to turn off in the current
    timepoint *t*. In this case, the relevant timepoints would be t-1 and
    t-2. By the time we reach t-3, we will have reached the 4-hour minimum
    up/down time, so t-3 will not be relevant for the minimum up time
    constraint in timepoint *t*.
    """

    # The first possible relevant timepoint is the current timepoint
    relevant_tmps = [tmp]
    relevant_linked_tmps = []
    # The first possible linked timepoint is 0
    linked_tmp = 0

    # If we have already reached the first timepoint of a horizon in a
    # linear boundary type we'll just pass, as there are no more relevant
    # timepoints to add
    if check_if_boundary_type_and_first_timepoint(
            mod=mod,
            tmp=tmp,
            balancing_type=mod.balancing_type_project[g],
            boundary_type="linear"):
        pass  # no more relevant timepoints, keep list limited to *t*
    # If we have already reached the first timepoint in a linked horizon
    # setting, we'll immediately move on to the linked timepoints without
    # looking for a previous timepoint
    elif check_if_boundary_type_and_first_timepoint(
            mod=mod,
            tmp=tmp,
            balancing_type=mod.balancing_type_project[g],
            boundary_type="linked"):
        # Add the first linked timepoint's duration to hours_from_tmp
        hours_from_tmp = mod.hrs_in_linked_tmp[linked_tmp]
        # If we haven't exceeded the min time yet, the first linked
        # timepoint is relevant, so we'll add it and move on to the
        # next one
        while hours_from_tmp < min_time:
            relevant_linked_tmps.append(linked_tmp)
            # If this is the furthest linked timepoint, break out of
            # the linked timepoints loop; otherwise, move on to the next
            # linked timepoint
            if linked_tmp == mod.furthest_linked_tmp:
                break
            else:
                hours_from_tmp += mod.hrs_in_linked_tmp[linked_tmp]
                linked_tmp += -1
    # If we haven't reached the first timepoint of a linear or linked
    # horizon, we'll look for the previous timepoint
    else:
        # The next possible relevant timepoint is the previous timepoint,
        # so we'll check its duration (if it's longer than or equal to the
        # minimum up/down time, we'll break out of the loop immediately)
        relevant_tmp = mod.prev_tmp[tmp, mod.balancing_type_project[g]]
        hours_from_tmp = \
            mod.hrs_in_tmp[
                mod.prev_tmp[tmp, mod.balancing_type_project[g]]]

        while hours_from_tmp < min_time:
            # If we haven't exceed the minimum up/down time yet, this timepoint
            # is relevant and we add it to our list
            relevant_tmps.append(relevant_tmp)

            # In a 'linear' horizon setting, once we reach the first
            # timepoint of the horizon, we break out of the loop since there
            # are no more timepoints to consider
            if check_if_boundary_type_and_first_timepoint(
                    mod=mod,
                    tmp=relevant_tmp,
                    balancing_type=mod.balancing_type_project[g],
                    boundary_type="linear"):
                break
            # In a 'circular' horizon setting, once we reach timepoint *t*,
            # we break out of the loop since there are no more timepoints to
            # consider (we have already added all horizon timepoints as
            # relevant)
            elif check_boundary_type(
                    mod=mod,
                    tmp=tmp,
                    balancing_type=mod.balancing_type_project[g],
                    boundary_type="circular") and relevant_tmp == tmp:
                break
            # TODO: only allow the first horizon of a subproblem to have
            #  linked timepoints
            # In a 'linked' horizon setting, once we reach the first
            # timepoint of the horizon, we'll start adding the linked
            # timepoints until we reach the target min time
            elif check_if_boundary_type_and_first_timepoint(
                    mod=mod,
                    tmp=relevant_tmp,
                    balancing_type=mod.balancing_type_project[g],
                    boundary_type="linked"):
                # Add the first linked timepoint's duration to hours_from_tmp
                hours_from_tmp += mod.hrs_in_linked_tmp[linked_tmp]
                # If we haven't exceeded the min time yet, the first linked
                # timepoint is relevant, so we'll add it and move on to the
                # next one
                while hours_from_tmp < min_time:
                    relevant_linked_tmps.append(linked_tmp)
                    # If this is the furthest linked timepoint, break out of
                    # the linked timepoints loop; otherwise, move on to the
                    # next linked timepoint
                    if linked_tmp == mod.furthest_linked_tmp:
                        break
                    else:
                        hours_from_tmp += mod.hrs_in_linked_tmp[linked_tmp]
                        linked_tmp += -1
                # Break out from the outer while loop when done with the
                # linked timepoints
                break
            # Otherwise, we move on to the relevant timepoint's previous
            # timepoint and will add that timepoint's duration to
            # hours_from_tmp
            else:
                hours_from_tmp += \
                    mod.hrs_in_tmp[
                        mod.prev_tmp[
                            relevant_tmp, mod.balancing_type_project[g]
                        ]
                    ]
                relevant_tmp = mod.prev_tmp[relevant_tmp,
                                            mod.balancing_type_project[g]]

    return relevant_tmps, relevant_linked_tmps