Exemplo n.º 1
0
def _add_interface_violations(lazy_violations, flows, mb, md, solver,
                              ptdf_options, PTDF, model, baseMVA,
                              persistent_solver, rel_ptdf_tol, abs_ptdf_tol,
                              time, prepend_str, obj_multi):
    ## in case there's no interfaces
    if not hasattr(mb, 'ineq_pf_interface_bounds'):
        return
    constr = mb.ineq_pf_interface_bounds
    int_viol_in_mb = mb._interfaces_monitored
    for i, i_n in _iter_over_int_viol_set(
            lazy_violations.interface_lazy_violations, mb, PTDF, abs_ptdf_tol,
            rel_ptdf_tol):
        minimum_limit = PTDF.interface_min_limits[i]
        maximum_limit = PTDF.interface_max_limits[i]
        if flows.PFV_I is None:
            logger.debug(
                prepend_str +
                _generate_flow_monitor_message('interface', i_n, time=time))
        else:
            logger.debug(prepend_str + _generate_flow_monitor_message(
                'interface', i_n, flows.PFV_I[i], minimum_limit, maximum_limit,
                baseMVA, time))
        constr[i_n], new_slacks = _generate_interface_bounds(
            mb, i_n, minimum_limit, maximum_limit)
        int_viol_in_mb.append(i)
        if new_slacks:
            m = model
            obj_coef = m.TimePeriodLengthHours * m.InterfaceLimitPenalty[i_n]

            if persistent_solver:
                m_model = m.model()
                if m is not m_model and obj_multi is None:
                    raise RuntimeError(
                        "Cannot add lazy var for interface slacks if part of a larger model"
                    )
                if obj_multi is not None:
                    obj_coef = obj_multi * obj_coef
                ## update the objective through the add_column method
                solver.add_column(m_model, mb.pfi_slack_pos[i_n], obj_coef, [],
                                  [])
                solver.add_column(m_model, mb.pfi_slack_neg[i_n], obj_coef, [],
                                  [])
            else:
                m.InterfaceViolationCost[time].expr += (obj_coef*mb.pfi_slack_pos[i_n] + \
                                                        obj_coef*mb.pfi_slack_neg[i_n] )
        if persistent_solver:
            solver.add_constraint(constr[i_n])
Exemplo n.º 2
0
def _add_contingency_violations(lazy_violations, flows, mb, md, solver,
                                ptdf_options, PTDF, model, baseMVA,
                                persistent_solver, rel_ptdf_tol, abs_ptdf_tol,
                                time, prepend_str, obj_multi):
    ## in case there's no contingencies
    if not hasattr(mb, 'ineq_pf_contingency_branch_thermal_bounds'):
        return
    constr = mb.ineq_pf_contingency_branch_thermal_bounds
    contingencies_monitored = mb._contingencies_monitored
    for cn, bn, i_b in _iter_over_cont_viol_set(
            lazy_violations.contingency_lazy_violations, mb, PTDF,
            abs_ptdf_tol, rel_ptdf_tol):
        emergency_thermal_limit = PTDF.contingency_limits_array_masked[i_b]
        logger.debug(
            prepend_str +
            _generate_flow_monitor_message('contingency', (cn, bn), time=time))
        constr[cn, bn], new_slacks = _generate_contingency_bounds(
            mb, (cn, bn), -emergency_thermal_limit, emergency_thermal_limit)
        contingencies_monitored.append((cn, i_b))
        if new_slacks:
            m = model
            obj_coef = m.TimePeriodLengthHours * m.SystemContingencyLimitPenalty

            if persistent_solver:
                m_model = m.model()
                if m is not m_model and obj_multi is None:
                    raise RuntimeError(
                        "Cannot add lazy var for branch contingency slacks if part of a larger model"
                    )
                if obj_multi is not None:
                    obj_coef = obj_multi * obj_coef
                ## update the objective through the add_column method
                solver.add_column(m_model, mb.pfc_slack_pos[cn, bn], obj_coef,
                                  [], [])
                solver.add_column(m_model, mb.pfc_slack_neg[cn, bn], obj_coef,
                                  [], [])
            else:
                m.ContingencyViolationCost[time].expr += (obj_coef*mb.pfc_slack_pos[cn,bn] + \
                                                          obj_coef*mb.pfc_slack_neg[cn,bn] )
        if persistent_solver:
            solver.add_constraint(constr[cn, bn])
Exemplo n.º 3
0
def remove_inactive(mb, solver, time=None, prepend_str=""):
    model = mb.model()
    PTDF = mb._PTDF
    ptdf_options = model._ptdf_options
    baseMVA = model.model_data.data['system']['baseMVA']

    slack_tol = ptdf_options['active_flow_tol']

    persistent_solver = isinstance(solver, PersistentSolver)

    ## get the lines we're monitoring
    idx_monitored = mb._idx_monitored
    interfaces_monitored = mb._interfaces_monitored

    ## get the branchnname to index map
    branchname_index_map = PTDF.branchname_to_index_masked_map
    interfacename_index_map = PTDF.interfacename_to_index_map

    ## branches
    branches = model.model_data.data['elements']['branch']
    interfaces = model.model_data.data['elements']['interface']

    constr_to_remove = list()

    for bn, constr in mb.ineq_pf_branch_thermal_bounds.items():
        ## don't take out branches we were told to monitor
        if 'lazy' in branches[bn] and not branches[bn]['lazy']:
            continue
        slack = constr.slack()
        if slack_tol <= abs(slack):
            logger.debug(prepend_str + _generate_flow_monitor_remove_message(
                'branch', bn, abs(slack), baseMVA, time))
            constr_to_remove.append(constr)
            ## remove the index from the lines we're monitoring
            idx_monitored.remove(branchname_index_map[bn])

    for i_n, constr in mb.ineq_pf_interface_bounds.items():
        ## don't take out branches we were told to monitor
        if 'lazy' in interfaces[i_n] and not interfaces[i_n]['lazy']:
            continue
        slack = constr.slack()
        if slack_tol <= abs(slack):
            logger.debug(prepend_str + _generate_flow_monitor_remove_message(
                'interface', i_n, abs(slack), baseMVA, time))
            constr_to_remove.append(constr)
            ## remove the index from the lines we're monitoring
            interfaces_monitored.remove(interfacename_index_map[i_n])

    msg = prepend_str + "removing {} inactive transmission constraint(s)".format(
        len(constr_to_remove))
    if time is not None:
        msg += " at time {}".format(time)
    logger.debug(msg)

    for constr in constr_to_remove:
        if persistent_solver:
            solver.remove_constraint(constr)
        del constr
    return len(constr_to_remove)
Exemplo n.º 4
0
def remove_inactive(mb, solver, time=None, prepend_str=""):
    model = mb.model()
    PTDF = mb._PTDF
    ptdf_options = model._ptdf_options
    baseMVA = model.model_data.data['system']['baseMVA']

    slack_tol = ptdf_options['active_flow_tol']

    persistent_solver = isinstance(solver, PersistentSolver)

    ## get the lines we're monitoring
    gt_idx_monitored = mb._gt_idx_monitored
    lt_idx_monitored = mb._lt_idx_monitored

    ## get the branchnname to index map
    branchname_index_map = PTDF.branchname_to_index_masked_map

    constr_to_remove = list()

    for bn, constr in mb.ineq_pf_branch_thermal_lb.items():
        slack = constr.slack()
        if slack_tol <= abs(slack):
            logger.debug(prepend_str + _generate_branch_remove_message(
                'LB', bn, abs(slack), baseMVA, time))
            constr_to_remove.append(constr)
            ## remove the index from the lines we're monitoring
            lt_idx_monitored.remove(branchname_index_map[bn])

    for bn, constr in mb.ineq_pf_branch_thermal_ub.items():
        slack = constr.slack()
        if slack_tol <= abs(slack):
            logger.debug(prepend_str + _generate_branch_remove_message(
                'UB', bn, abs(slack), baseMVA, time))
            constr_to_remove.append(constr)
            ## remove the index from the lines we're monitoring
            gt_idx_monitored.remove(branchname_index_map[bn])

    msg = prepend_str + "removing {} inactive transmission constraint(s)".format(
        len(constr_to_remove))
    if time is not None:
        msg += " at time {}".format(time)
    logger.debug(msg)

    for constr in constr_to_remove:
        if persistent_solver:
            solver.remove_constraint(constr)
        del constr
    return len(constr_to_remove)
Exemplo n.º 5
0
def add_violations(lazy_violations,
                   flows,
                   mb,
                   md,
                   solver,
                   ptdf_options,
                   PTDF,
                   time=None,
                   prepend_str=""):

    if time is None:
        model = mb
    else:
        model = mb.parent_block()

    baseMVA = md.data['system']['baseMVA']

    persistent_solver = isinstance(solver, PersistentSolver)

    ## static information between runs
    rel_ptdf_tol = ptdf_options['rel_ptdf_tol']
    abs_ptdf_tol = ptdf_options['abs_ptdf_tol']

    constr = mb.ineq_pf_branch_thermal_bounds
    viol_in_mb = mb._idx_monitored
    for i, bn in _iter_over_viol_set(lazy_violations.branch_lazy_violations,
                                     mb, PTDF, abs_ptdf_tol, rel_ptdf_tol):
        thermal_limit = PTDF.branch_limits_array_masked[i]
        if flows.PFV is None:
            logger.debug(
                prepend_str +
                _generate_flow_monitor_message('branch', bn, time=time))
        else:
            logger.debug(prepend_str + _generate_flow_monitor_message(
                'branch', bn, flows.PFV[i], -thermal_limit, thermal_limit,
                baseMVA, time))

        constr[bn], new_slacks = _generate_branch_thermal_bounds(
            mb, bn, thermal_limit)
        viol_in_mb.append(i)
        if new_slacks:
            m = model
            obj_coef = m.TimePeriodLengthHours * m.BranchLimitPenalty[bn]

            if persistent_solver:
                if m is not m.model():
                    raise RuntimeError(
                        "Cannot add lazy var for branch slacks if part of a larger model"
                    )
                ## update the objective through the add_column method
                solver.add_column(m, mb.pf_slack_pos[bn], obj_coef, [], [])
                solver.add_column(m, mb.pf_slack_neg[bn], obj_coef, [], [])
            else:
                m.BranchViolationCost[time].expr += ( obj_coef*mb.pf_slack_pos[bn] + \
                                                      obj_coef*mb.pf_slack_neg[bn] )
        if persistent_solver:
            solver.add_constraint(constr[bn])

    _add_interface_violations(lazy_violations, flows, mb, md, solver,
                              ptdf_options, PTDF, model, baseMVA,
                              persistent_solver, rel_ptdf_tol, abs_ptdf_tol,
                              time, prepend_str)
    _add_contingency_violations(lazy_violations, flows, mb, md, solver,
                                ptdf_options, PTDF, model, baseMVA,
                                persistent_solver, rel_ptdf_tol, abs_ptdf_tol,
                                time, prepend_str)
Exemplo n.º 6
0
def check_violations(mb, md, PTDF, max_viol_add, time=None, prepend_str=""):

    if time is None:  # DCOPF
        active_slack_tol = mb._ptdf_options['active_flow_tol']
    else:  # Unit Commitment
        active_slack_tol = mb.parent_block()._ptdf_options['active_flow_tol']

    ## PFV -- power flow vector
    ## PFV_I -- interface power flow vector
    ## VA -- bus voltage angle vector
    PFV, PFV_I, VA = PTDF.calculate_masked_PFV(mb)

    violations_store = _MaximalViolationsStore(max_viol_add=max_viol_add,
                                               md=md,
                                               time=time,
                                               prepend_str=prepend_str)

    if len(PTDF.branches_keys_masked) > 0:
        violations_store.check_and_add_violations(
            'branch', PFV, mb.pf, PTDF.lazy_branch_limits,
            PTDF.enforced_branch_limits, -PTDF.lazy_branch_limits,
            -PTDF.enforced_branch_limits, mb._idx_monitored,
            PTDF.branches_keys_masked)

    if len(PTDF.interface_keys) > 0:
        violations_store.check_and_add_violations(
            'interface', PFV_I, mb.pfi, PTDF.lazy_interface_max_limits,
            PTDF.enforced_interface_max_limits, PTDF.lazy_interface_min_limits,
            PTDF.enforced_interface_min_limits, mb._interfaces_monitored,
            PTDF.interface_keys)

    if PTDF.contingencies and \
           violations_store.total_violations == 0:
        ## NOTE: checking contingency constraints in general could be very expensive
        ##       we probably want to delay doing so until we have a nearly transmission feasible
        ##       solution

        ## For each contingency, we'll only calculate the difference in flow,
        ## and check this against the difference in bounds, i.e.,

        ## power_flow_contingency == PFV + PFV_delta_c
        ## -rate_c <= power_flow_contingency <= +rate_c
        ## <===>
        ## -rate_c - PFV <= PFV_delta_c <= +rate_c - PFV
        ## <===>
        ## contingency_limits_lower <= PFV_delta_c <= contingency_limits_upper
        ## and
        ## contingency_limits_lower == -rate_c - PFV; contingency_limits_upper == rate_c - PFV

        ## In this way, we avoid (number of contingenies) adds PFV+PFV_delta_c

        logger.debug("Checking contingency flows...")
        lazy_contingency_limits_upper = PTDF.lazy_contingency_limits - PFV
        lazy_contingency_limits_lower = -PTDF.lazy_contingency_limits - PFV
        enforced_contingency_limits_upper = PTDF.enforced_contingency_limits - PFV
        enforced_contingency_limits_lower = -PTDF.enforced_contingency_limits - PFV
        for cn in PTDF.contingency_compensators:
            PFV_delta = PTDF.calculate_masked_PFV_delta(cn, PFV, VA)
            violations_store.check_and_add_violations(
                'contingency',
                PFV_delta,
                mb.pfc,
                lazy_contingency_limits_upper,
                enforced_contingency_limits_upper,
                lazy_contingency_limits_lower,
                enforced_contingency_limits_lower,
                mb._contingencies_monitored,
                PTDF.branches_keys_masked,
                outer_name=cn,
                PFV=PFV)

    logger.debug(
        f"branches_monitored: {mb._idx_monitored}\n"
        f"interfaces_monitored: {mb._interfaces_monitored}\n"
        f"contingencies_monitored: {mb._contingencies_monitored}\n"
        f"Violations being added: {violations_store.violations_store}\n"
        f"Violations in model: {violations_store.monitored_violations}\n")

    viol_lazy = _LazyViolations(
        branch_lazy_violations=set(
            violations_store.get_violations_named('branch')),
        interface_lazy_violations=set(
            violations_store.get_violations_named('interface')),
        contingency_lazy_violations=set(
            violations_store.get_violations_named('contingency')))
    flows = _CalculatedFlows(PFV=PFV, PFV_I=PFV_I)

    return flows, violations_store.total_violations, violations_store.monitored_violations, viol_lazy
Exemplo n.º 7
0
def add_violations(viol_lazy,
                   int_viol_lazy,
                   PFV,
                   PFV_I,
                   mb,
                   md,
                   solver,
                   ptdf_options,
                   PTDF,
                   time=None,
                   prepend_str=""):

    model = mb.model()

    baseMVA = md.data['system']['baseMVA']

    persistent_solver = isinstance(solver, PersistentSolver)

    ## static information between runs
    rel_ptdf_tol = ptdf_options['rel_ptdf_tol']
    abs_ptdf_tol = ptdf_options['abs_ptdf_tol']

    constr = mb.ineq_pf_branch_thermal_bounds
    viol_in_mb = mb._idx_monitored
    for i, bn in _iter_over_viol_set(viol_lazy, mb, PTDF, abs_ptdf_tol,
                                     rel_ptdf_tol):
        thermal_limit = PTDF.branch_limits_array_masked[i]
        if PFV is None:
            logger.debug(
                prepend_str +
                _generate_flow_monitor_message('branch', bn, time=time))
        else:
            logger.debug(prepend_str + _generate_flow_monitor_message(
                'branch', bn, PFV[i], -thermal_limit, thermal_limit, baseMVA,
                time))
        constr[bn] = (-thermal_limit, mb.pf[bn], thermal_limit)
        viol_in_mb.append(i)
        if persistent_solver:
            solver.add_constraint(constr[bn])

    ## in case there's no interfaces
    if not hasattr(mb, 'ineq_pf_interface_bounds'):
        return
    constr = mb.ineq_pf_interface_bounds
    int_viol_in_mb = mb._interfaces_monitored
    for i, i_n in _iter_over_int_viol_set(int_viol_lazy, mb, PTDF,
                                          abs_ptdf_tol, rel_ptdf_tol):
        minimum_limit = PTDF.interface_min_limits[i]
        maximum_limit = PTDF.interface_max_limits[i]
        if PFV_I is None:
            logger.debug(
                prepend_str +
                _generate_flow_monitor_message('interface', i_n, time=time))
        else:
            logger.debug(prepend_str + _generate_flow_monitor_message(
                'interface', i_n, PFV_I[i], minimum_limit, maximum_limit,
                baseMVA, time))
        constr[i_n] = (minimum_limit, mb.pfi[i_n], maximum_limit)
        int_viol_in_mb.append(i)
        if persistent_solver:
            solver.add_constraint(constr[i_n])
Exemplo n.º 8
0
def add_violations(gt_viol_lazy,
                   lt_viol_lazy,
                   PFV,
                   mb,
                   md,
                   solver,
                   ptdf_options,
                   PTDF,
                   time=None,
                   prepend_str=""):

    model = mb.model()

    baseMVA = md.data['system']['baseMVA']

    persistent_solver = isinstance(solver, PersistentSolver)

    ## static information between runs
    rel_ptdf_tol = ptdf_options['rel_ptdf_tol']
    abs_ptdf_tol = ptdf_options['abs_ptdf_tol']

    ## helper for generating pf
    def _iter_over_viol_set(viol_set):
        for i in viol_set:
            bn = PTDF.branches_keys_masked[i]
            if mb.pf[bn].expr is None:
                expr = libbranch.get_power_flow_expr_ptdf_approx(
                    mb,
                    bn,
                    PTDF,
                    abs_ptdf_tol=abs_ptdf_tol,
                    rel_ptdf_tol=rel_ptdf_tol)
                mb.pf[bn] = expr
            yield i, bn

    constr = mb.ineq_pf_branch_thermal_lb
    lt_viol_in_mb = mb._lt_idx_monitored
    for i, bn in _iter_over_viol_set(lt_viol_lazy):
        thermal_limit = PTDF.branch_limits_array_masked[i]
        if PFV is None:
            logger.debug(prepend_str +
                         _generate_flow_monitor_message('LB', bn, time=time))
        else:
            logger.debug(prepend_str + _generate_flow_monitor_message(
                'LB', bn, PFV[i], -thermal_limit, baseMVA, time))
        constr[bn] = (-thermal_limit, mb.pf[bn], None)
        lt_viol_in_mb.append(i)
        if persistent_solver:
            solver.add_constraint(constr[bn])

    constr = mb.ineq_pf_branch_thermal_ub
    gt_viol_in_mb = mb._gt_idx_monitored
    for i, bn in _iter_over_viol_set(gt_viol_lazy):
        thermal_limit = PTDF.branch_limits_array_masked[i]
        if PFV is None:
            logger.debug(prepend_str +
                         _generate_flow_monitor_message('UB', bn, time=time))
        else:
            logger.debug(prepend_str + _generate_flow_monitor_message(
                'UB', bn, PFV[i], thermal_limit, baseMVA, time))
        constr[bn] = (None, mb.pf[bn], thermal_limit)
        gt_viol_in_mb.append(i)
        if persistent_solver:
            solver.add_constraint(constr[bn])
Exemplo n.º 9
0
def remove_inactive(mb, solver, time=None, prepend_str=""):
    if time is None:  # DCOPF
        model = mb
    else:  # UC
        model = mb.parent_block()
    PTDF = mb._PTDF
    ptdf_options = model._ptdf_options
    baseMVA = model.model_data.data['system']['baseMVA']

    slack_tol = ptdf_options['active_flow_tol']

    persistent_solver = isinstance(solver, PersistentSolver)

    ## get the lines we're monitoring
    idx_monitored = mb._idx_monitored
    interfaces_monitored = mb._interfaces_monitored
    contingencies_monitored = mb._contingencies_monitored

    ## get the branchnname to index map
    branchname_index_map = PTDF.branchname_to_index_masked_map
    interfacename_index_map = PTDF.interfacename_to_index_map

    ## branches
    branches = model.model_data.data['elements']['branch']
    interfaces = model.model_data.data['elements']['interface']

    # list of tuples -- each tuple is ( key, indexed_constraint, constraint_data )
    constr_to_remove = list()

    for bn, constr in mb.ineq_pf_branch_thermal_bounds.items():
        ## don't take out branches we were told to monitor
        if 'lazy' in branches[bn] and not branches[bn]['lazy']:
            continue
        slack = constr.slack()
        if slack_tol <= abs(slack):
            logger.debug(prepend_str + _generate_flow_monitor_remove_message(
                'branch', bn, abs(slack), baseMVA, time))
            constr_to_remove.append(
                (bn, mb.ineq_pf_branch_thermal_bounds, constr))
            ## remove the index from the lines we're monitoring
            idx_monitored.remove(branchname_index_map[bn])

    for i_n, constr in mb.ineq_pf_interface_bounds.items():
        ## don't take out branches we were told to monitor
        if 'lazy' in interfaces[i_n] and not interfaces[i_n]['lazy']:
            continue
        slack = constr.slack()
        if slack_tol <= abs(slack):
            logger.debug(prepend_str + _generate_flow_monitor_remove_message(
                'interface', i_n, abs(slack), baseMVA, time))
            constr_to_remove.append((i_n, mb.ineq_pf_interface_bounds, constr))
            ## remove the index from the lines we're monitoring
            interfaces_monitored.remove(interfacename_index_map[i_n])

    for name, constr in mb.ineq_pf_contingency_branch_thermal_bounds.items():
        slack = constr.slack()
        if slack_tol <= abs(slack):
            logger.debug(prepend_str + _generate_flow_monitor_remove_message(
                'contingeny', name, abs(slack), baseMVA, time))
            constr_to_remove.append(
                (name, mb.ineq_pf_contingency_branch_thermal_bounds, constr))
            ## remove the index from the lines we're monitoring
            contingencies_monitored.remove(
                (name[0], branchname_index_map[name[1]]))  ## TODO: name?

    msg = prepend_str + "removing {} inactive transmission constraint(s)".format(
        len(constr_to_remove))
    if time is not None:
        msg += " at time {}".format(time)
    logger.debug(msg)

    for key, indexed_constraint, constr_data in constr_to_remove:
        if persistent_solver:
            solver.remove_constraint(constr_data)
        del indexed_constraint[key]
    return len(constr_to_remove)