Beispiel #1
0
def create_economic_dispatch_approx_model(model_data):
    md = tx_utils.scale_ModelData_to_pu(model_data)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    gen_attrs = md.attributes(element_type='generator')
    bus_attrs = md.attributes(element_type='bus')
    branch_attrs = md.attributes(element_type='branch')
    load_attrs = md.attributes(element_type='load')
    shunt_attrs = md.attributes(element_type='shunt')

    inlet_branches_by_bus, outlet_branches_by_bus = \
        tx_utils.inlet_outlet_branches_by_bus(branches, buses)
    gens_by_bus = tx_utils.gens_in_service_by_bus(buses, gens)

    model = pe.ConcreteModel()

    ### declare (and fix) the loads at the buses
    bus_p_loads, _ = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads)
    model.pl.fix()

    ### declare the fixed shunts at the buses
    _, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(buses, shunts)

    ### declare the generator real power
    pg_init = {
        k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0
        for k in gen_attrs['pg']
    }
    libgen.declare_var_pg(model,
                          gen_attrs['names'],
                          initialize=pg_init,
                          bounds=zip_items(gen_attrs['p_min'],
                                           gen_attrs['p_max']))

    ### declare the p balance
    libbus.declare_eq_p_balance_ed(model=model,
                                   index_set=bus_attrs['names'],
                                   bus_p_loads=bus_p_loads,
                                   gens_by_bus=gens_by_bus,
                                   bus_gs_fixed_shunts=bus_gs_fixed_shunts)

    ### declare the generator cost objective
    libgen.declare_expression_pgqg_operating_cost(model=model,
                                                  index_set=gen_attrs['names'],
                                                  p_costs=gen_attrs['p_cost'])

    obj_expr = sum(model.pg_operating_cost[gen_name]
                   for gen_name in model.pg_operating_cost)

    model.obj = pe.Objective(expr=obj_expr)

    return model
Beispiel #2
0
def _setup_egret_network_model(block, tm):
    m = block.model()

    ## this is not the "real" gens by bus, but the
    ## index of net injections from the UC model
    gens_by_bus = block.gens_by_bus

    ### declare (and fix) the loads at the buses
    bus_p_loads = {b: value(m.Demand[b, tm]) for b in m.Buses}

    ## index of net injections from the UC model
    libbus.declare_var_pl(block, m.Buses, initialize=bus_p_loads)
    block.pl.fix()

    bus_gs_fixed_shunts = m._bus_gs_fixed_shunts

    return m, gens_by_bus, bus_p_loads, bus_gs_fixed_shunts
Beispiel #3
0
def _copperplate_approx_network_model(block,tm):
    m = block.model()

    ## this is not the "real" gens by bus, but the
    gens_by_bus = block.gens_by_bus

    ### declare (and fix) the loads at the buses
    bus_p_loads = {b: value(m.Demand[b,tm]) for b in m.Buses}

    ## index of net injections from the UC model
    libbus.declare_var_pl(block, m.Buses, initialize=bus_p_loads)
    block.pl.fix()

    bus_gs_fixed_shunts = m._bus_gs_fixed_shunts

    ### declare the p balance
    libbus.declare_eq_p_balance_ed(model=block,
                                   index_set=m.Buses,
                                   bus_p_loads=bus_p_loads,
                                   gens_by_bus=gens_by_bus,
                                   bus_gs_fixed_shunts=bus_gs_fixed_shunts,
                                   )
Beispiel #4
0
def _btheta_dcopf_network_model(md,block):
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    bus_attrs = md.attributes(element_type='bus')
    branch_attrs = md.attributes(element_type='branch')

    inlet_branches_by_bus, outlet_branches_by_bus = \
        tx_utils.inlet_outlet_branches_by_bus(branches, buses)

    ## this is not the "real" gens by bus, but the
    ## index of net injections from the UC model
    gens_by_bus = block.gens_by_bus

    ### declare (and fix) the loads at the buses
    bus_p_loads, _ = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(block, bus_attrs['names'], initialize=bus_p_loads)
    block.pl.fix()

    ### declare the fixed shunts at the buses
    _, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(buses, shunts)

    ### declare the polar voltages
    va_bounds = {k: (-pi, pi) for k in bus_attrs['names']}
    libbus.declare_var_va(block, bus_attrs['names'], initialize=None,
                          bounds=va_bounds
                          )

    ### fix the reference bus
    ref_bus = md.data['system']['reference_bus']
    block.va[ref_bus].fix(0.0)

    ref_angle = md.data['system']['reference_bus_angle']
    if ref_angle != 0.0:
        raise ValueError('The BTHETA DCOPF formulation currently only supports'
                         ' a reference bus angle of 0 degrees, but an angle'
                         ' of {} degrees was found.'.format(ref_angle))

    p_max = {k: branches[k]['rating_long_term'] for k in branches.keys()}
    p_lbub = {k: (-p_max[k],p_max[k]) for k in branches.keys()}
    pf_bounds = p_lbub

    libbranch.declare_var_pf(model=block,
                             index_set=branch_attrs['names'],
                             initialize=None,
                             bounds=pf_bounds
                             )

    ### declare the branch power flow approximation constraints
    libbranch.declare_eq_branch_power_btheta_approx(model=block,
                                                    index_set=branch_attrs['names'],
                                                    branches=branches
                                                    )

    ### declare the p balance
    libbus.declare_eq_p_balance_dc_approx(model=block,
                                          index_set=bus_attrs['names'],
                                          bus_p_loads=bus_p_loads,
                                          gens_by_bus=gens_by_bus,
                                          bus_gs_fixed_shunts=bus_gs_fixed_shunts,
                                          inlet_branches_by_bus=inlet_branches_by_bus,
                                          outlet_branches_by_bus=outlet_branches_by_bus,
                                          approximation_type=ApproximationType.BTHETA
                                          )

    ### declare the real power flow limits
    libbranch.declare_ineq_p_branch_thermal_lbub(model=block,
                                                 index_set=branch_attrs['names'],
                                                 branches=branches,
                                                 p_thermal_limits=p_max,
                                                 approximation_type=ApproximationType.BTHETA
                                                 )

    ### declare angle difference limits on interconnected buses
    libbranch.declare_ineq_angle_diff_branch_lbub(model=block,
                                                  index_set=branch_attrs['names'],
                                                  branches=branches,
                                                  coordinate_type=CoordinateType.POLAR
                                                  )

    return block
Beispiel #5
0
def create_hot_start_lpac_model(model_data,
                                voltages,
                                lower_bound=-pi / 3,
                                upper_bound=pi / 3,
                                cosine_segment_count=20,
                                include_feasibility_slack=False,
                                mode="uniform"):
    """
	The hot start LPAC model assumes that voltages are known, e.g. from an AC base point solution.
	"""
    ###Grid data
    md = model_data.clone_in_service()
    tx_utils.scale_ModelData_to_pu(md, inplace=True)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    gen_attrs = md.attributes(element_type='generator')
    bus_attrs = md.attributes(element_type='bus')
    branch_attrs = md.attributes(element_type='branch')

    inlet_branches_by_bus, outlet_branches_by_bus = \
           tx_utils.inlet_outlet_branches_by_bus(branches, buses)

    gens_by_bus = tx_utils.gens_by_bus(buses, gens)

    model = pe.ConcreteModel()

    ###declare (and fix) the voltage magnitudes and squares of voltage magnitudes

    bus_voltage_magnitudes = voltages  #Assumes voltages is given as a dictionary
    libbus.declare_var_vm(model,
                          bus_attrs['names'],
                          initialize=bus_voltage_magnitudes)
    model.vm.fix()

    libbus.declare_var_vmsq(
        model=model,
        index_set=bus_attrs['names'],
        initialize={k: v**2
                    for k, v in bus_attrs['vm'].items()},
        bounds=zip_items({k: v**2
                          for k, v in bus_attrs['v_min'].items()},
                         {k: v**2
                          for k, v in bus_attrs['v_max'].items()}))

    ### declare the polar voltages

    libbus.declare_var_va(model,
                          bus_attrs['names'],
                          initialize=bus_attrs['va'])

    ### declare the cosine approximation variables
    cos_hat_bounds = {k: (0, 1) for k in branch_attrs['names']}
    decl.declare_var('cos_hat',
                     model,
                     branch_attrs['names'],
                     bounds=cos_hat_bounds)

    ### fix the reference bus
    ref_bus = md.data['system']['reference_bus']
    #ref_angle = md.data['system']['reference_bus_angle']
    model.va[ref_bus].fix(radians(0.0))

    ### declare the fixed shunts at the buses
    bus_bs_fixed_shunts, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(
        buses, shunts)

    ### declare (and fix) the loads at the buses
    bus_p_loads, bus_q_loads = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads)
    libbus.declare_var_ql(model, bus_attrs['names'], initialize=bus_q_loads)
    model.pl.fix()
    model.ql.fix()

    ### include the feasibility slack for the bus balances
    p_rhs_kwargs = {}
    q_rhs_kwargs = {}
    if include_feasibility_slack:
        p_rhs_kwargs, q_rhs_kwargs, penalty_expr = _include_feasibility_slack(
            model, bus_attrs, gen_attrs, bus_p_loads, bus_q_loads)

### declare the generator real and reactive power
    pg_init = {
        k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0
        for k in gen_attrs['pg']
    }
    libgen.declare_var_pg(model,
                          gen_attrs['names'],
                          initialize=pg_init,
                          bounds=zip_items(gen_attrs['p_min'],
                                           gen_attrs['p_max']))

    qg_init = {
        k: (gen_attrs['q_min'][k] + gen_attrs['q_max'][k]) / 2.0
        for k in gen_attrs['qg']
    }
    libgen.declare_var_qg(model,
                          gen_attrs['names'],
                          initialize=qg_init,
                          bounds=zip_items(gen_attrs['q_min'],
                                           gen_attrs['q_max']))

    ### declare the current flows in the branches
    vr_init = {
        k: bus_attrs['vm'][k] * pe.cos(bus_attrs['va'][k])
        for k in bus_attrs['vm']
    }
    vj_init = {
        k: bus_attrs['vm'][k] * pe.sin(bus_attrs['va'][k])
        for k in bus_attrs['vm']
    }
    s_max = {k: branches[k]['rating_long_term'] for k in branches.keys()}
    s_lbub = dict()
    for k in branches.keys():
        if s_max[k] is None:
            s_lbub[k] = (None, None)
        else:
            s_lbub[k] = (-s_max[k], s_max[k])
    pf_bounds = s_lbub
    pt_bounds = s_lbub
    qf_bounds = s_lbub
    qt_bounds = s_lbub
    pf_init = dict()
    pt_init = dict()
    qf_init = dict()
    qt_init = dict()
    for branch_name, branch in branches.items():
        from_bus = branch['from_bus']
        to_bus = branch['to_bus']
        y_matrix = tx_calc.calculate_y_matrix_from_branch(branch)
        ifr_init = tx_calc.calculate_ifr(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        ifj_init = tx_calc.calculate_ifj(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        itr_init = tx_calc.calculate_itr(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        itj_init = tx_calc.calculate_itj(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        pf_init[branch_name] = tx_calc.calculate_p(ifr_init, ifj_init,
                                                   vr_init[from_bus],
                                                   vj_init[from_bus])
        pt_init[branch_name] = tx_calc.calculate_p(itr_init, itj_init,
                                                   vr_init[to_bus],
                                                   vj_init[to_bus])
        qf_init[branch_name] = tx_calc.calculate_q(ifr_init, ifj_init,
                                                   vr_init[from_bus],
                                                   vj_init[from_bus])
        qt_init[branch_name] = tx_calc.calculate_q(itr_init, itj_init,
                                                   vr_init[to_bus],
                                                   vj_init[to_bus])

    libbranch.declare_var_pf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pf_init,
                             bounds=pf_bounds)
    libbranch.declare_var_pt(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pt_init,
                             bounds=pt_bounds)
    libbranch.declare_var_qf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=qf_init,
                             bounds=qf_bounds)
    libbranch.declare_var_qt(model=model,
                             index_set=branch_attrs['names'],
                             initialize=qt_init,
                             bounds=qt_bounds)

    ####################
    #Constraints
    ####################

    ###Balance equations in a bus

    #p balance

    libbus.declare_eq_p_balance(model=model,
                                index_set=bus_attrs['names'],
                                bus_p_loads=bus_p_loads,
                                gens_by_bus=gens_by_bus,
                                bus_gs_fixed_shunts=bus_gs_fixed_shunts,
                                inlet_branches_by_bus=inlet_branches_by_bus,
                                outlet_branches_by_bus=outlet_branches_by_bus,
                                **p_rhs_kwargs)

    #q balance

    libbus.declare_eq_q_balance(model=model,
                                index_set=bus_attrs['names'],
                                bus_q_loads=bus_q_loads,
                                gens_by_bus=gens_by_bus,
                                bus_bs_fixed_shunts=bus_bs_fixed_shunts,
                                inlet_branches_by_bus=inlet_branches_by_bus,
                                outlet_branches_by_bus=outlet_branches_by_bus,
                                **q_rhs_kwargs)

    ### Power in a branch

    branch_con_set = decl.declare_set('_con_eq_p_q_lpac_branch_power', model,
                                      branch_attrs['names'])

    model.eq_pf_branch_t = pe.Constraint(branch_con_set)
    model.eq_pt_branch_t = pe.Constraint(branch_con_set)
    model.eq_qf_branch_t = pe.Constraint(branch_con_set)
    model.eq_qt_branch_t = pe.Constraint(branch_con_set)

    for branch_name in branch_con_set:
        branch = branches[branch_name]

        from_bus = branch['from_bus']
        to_bus = branch['to_bus']

        g = tx_calc.calculate_conductance(branch)
        b = tx_calc.calculate_susceptance(branch)

        model.eq_pf_branch_t[branch_name] = \
         model.pf[branch_name] == \
         g*model.vmsq[from_bus] - model.vm[from_bus]*model.vm[to_bus]*(g * model.cos_hat[branch_name] + b * (model.va[from_bus] - model.va[to_bus]))

        model.eq_pt_branch_t[branch_name] = \
         model.pt[branch_name] == \
         g*model.vmsq[to_bus] - model.vm[from_bus]*model.vm[to_bus]*(g * model.cos_hat[branch_name] + b * (model.va[to_bus] - model.va[from_bus]))

        model.eq_qf_branch_t[branch_name] = \
         model.qf[branch_name] == \
         -b*model.vmsq[from_bus] - model.vm[from_bus]*model.vm[to_bus]*(g*(model.va[from_bus] - model.va[to_bus]) - b*model.cos_hat[branch_name])

        model.eq_qt_branch_t[branch_name] = \
         model.qt[branch_name] == \
         -b*model.vmsq[to_bus] - model.vm[from_bus]*model.vm[to_bus]*(g*(model.va[to_bus] - model.va[from_bus]) - b*model.cos_hat[branch_name])

### Piecewise linear cosine constraints

    model.N = pe.Set(initialize=list(range(cosine_segment_count + 1)))

    declare_pwl_cosine_bounds(model=model,
                              index_set=branch_attrs['names'],
                              branches=branches,
                              lower_bound=lower_bound,
                              upper_bound=upper_bound,
                              cosine_segment_count=cosine_segment_count,
                              mode=mode)

    ### Objective is to maximize cosine hat variables

    obj_expr = sum(model.cos_hat[branch_name]
                   for branch_name in branch_attrs['names'])

    if include_feasibility_slack:
        obj_expr += penalty_expr

    model.obj = pe.Objective(expr=obj_expr)

    return model, md
Beispiel #6
0
def create_ptdf_losses_dcopf_model(model_data, include_feasibility_slack=False, ptdf_options=None):

    ptdf_options = lpu.populate_default_ptdf_options(ptdf_options)

    baseMVA = model_data.data['system']['baseMVA']
    lpu.check_and_scale_ptdf_options(ptdf_options, baseMVA)

    md = model_data.clone_in_service()
    tx_utils.scale_ModelData_to_pu(md, inplace = True)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    gen_attrs = md.attributes(element_type='generator')
    bus_attrs = md.attributes(element_type='bus')
    branch_attrs = md.attributes(element_type='branch')
    load_attrs = md.attributes(element_type='load')
    shunt_attrs = md.attributes(element_type='shunt')

    inlet_branches_by_bus, outlet_branches_by_bus = \
        tx_utils.inlet_outlet_branches_by_bus(branches, buses)
    gens_by_bus = tx_utils.gens_by_bus(buses, gens)

    model = pe.ConcreteModel()

    ### declare (and fix) the loads at the buses
    bus_p_loads, _ = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads)
    model.pl.fix()

    ### declare the fixed shunts at the buses
    _, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(buses, shunts)

    ### declare the generator real power
    pg_init = {k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0 for k in gen_attrs['pg']}
    libgen.declare_var_pg(model, gen_attrs['names'], initialize=pg_init,
                          bounds=zip_items(gen_attrs['p_min'], gen_attrs['p_max'])
                          )

    ### include the feasibility slack for the system balance
    p_rhs_kwargs = {}
    if include_feasibility_slack:
        p_rhs_kwargs, penalty_expr = _include_system_feasibility_slack(model, gen_attrs, bus_p_loads)

    ### declare net withdraw expression for use in PTDF power flows
    libbus.declare_expr_p_net_withdraw_at_bus(model=model,
                                              index_set=bus_attrs['names'],
                                              bus_p_loads=bus_p_loads,
                                              gens_by_bus=gens_by_bus,
                                              bus_gs_fixed_shunts=bus_gs_fixed_shunts,
                                              )

    ### declare the current flows in the branches
    p_max = {k: branches[k]['rating_long_term'] for k in branches.keys()}
    pfl_bounds = {k: (-p_max[k]**2,p_max[k]**2) for k in branches.keys()}
    pfl_init = {k: 0 for k in branches.keys()}

    ## Do and store PTDF calculation
    reference_bus = md.data['system']['reference_bus']
    ## We'll assume we have a solution to initialize from
    base_point = BasePointType.SOLUTION

    PTDF = ptdf_utils.PTDFLossesMatrix(branches, buses, reference_bus, base_point, ptdf_options)
    model._PTDF = PTDF
    model._ptdf_options = ptdf_options

    libbranch.declare_expr_pf(model=model,
                             index_set=branch_attrs['names'],
                             )

    libbranch.declare_var_pfl(model=model,
                              index_set=branch_attrs['names'],
                              initialize=pfl_init,
                              bounds=pfl_bounds
                             )

    ### declare the branch power flow approximation constraints
    libbranch.declare_eq_branch_power_ptdf_approx(model=model,
                                                  index_set=branch_attrs['names'],
                                                  PTDF=PTDF,
                                                  abs_ptdf_tol=ptdf_options['abs_ptdf_tol'],
                                                  rel_ptdf_tol=ptdf_options['rel_ptdf_tol'],
                                                  )

    ### declare the branch power loss approximation constraints
    libbranch.declare_eq_branch_loss_ptdf_approx(model=model,
                                                 index_set=branch_attrs['names'],
                                                 PTDF=PTDF,
                                                 abs_ptdf_tol=ptdf_options['abs_ptdf_tol'],
                                                 rel_ptdf_tol=ptdf_options['rel_ptdf_tol'],
                                                 )

    ### declare the p balance
    libbus.declare_eq_p_balance_ed(model=model,
                                   index_set=bus_attrs['names'],
                                   bus_p_loads=bus_p_loads,
                                   gens_by_bus=gens_by_bus,
                                   bus_gs_fixed_shunts=bus_gs_fixed_shunts,
                                   include_losses=branch_attrs['names'],
                                   **p_rhs_kwargs
                                   )

    ### declare the real power flow limits
    libbranch.declare_ineq_p_branch_thermal_lbub(model=model,
                                                 index_set=branch_attrs['names'],
                                                 branches=branches,
                                                 p_thermal_limits=p_max,
                                                 approximation_type=ApproximationType.PTDF
                                                 )

    ### declare the generator cost objective
    libgen.declare_expression_pgqg_operating_cost(model=model,
                                                  index_set=gen_attrs['names'],
                                                  p_costs=gen_attrs['p_cost']
                                                  )

    obj_expr = sum(model.pg_operating_cost[gen_name] for gen_name in model.pg_operating_cost)
    if include_feasibility_slack:
        obj_expr += penalty_expr

    model.obj = pe.Objective(expr=obj_expr)

    return model, md
Beispiel #7
0
def create_psv_acopf_model(model_data, include_feasibility_slack=False):
    md = model_data.clone_in_service()
    tx_utils.scale_ModelData_to_pu(md, inplace=True)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    gen_attrs = md.attributes(element_type='generator')
    bus_attrs = md.attributes(element_type='bus')
    branch_attrs = md.attributes(element_type='branch')
    load_attrs = md.attributes(element_type='load')
    shunt_attrs = md.attributes(element_type='shunt')

    inlet_branches_by_bus, outlet_branches_by_bus = \
        tx_utils.inlet_outlet_branches_by_bus(branches, buses)
    gens_by_bus = tx_utils.gens_by_bus(buses, gens)

    model = pe.ConcreteModel()

    ### declare (and fix) the loads at the buses
    bus_p_loads, bus_q_loads = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads)
    libbus.declare_var_ql(model, bus_attrs['names'], initialize=bus_q_loads)
    model.pl.fix()
    model.ql.fix()

    ### declare the fixed shunts at the buses
    bus_bs_fixed_shunts, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(
        buses, shunts)

    ### declare the polar voltages
    libbus.declare_var_vm(model,
                          bus_attrs['names'],
                          initialize=bus_attrs['vm'],
                          bounds=zip_items(bus_attrs['v_min'],
                                           bus_attrs['v_max']))

    libbus.declare_expr_vmsq(model=model,
                             index_set=bus_attrs['names'],
                             coordinate_type=CoordinateType.POLAR)

    va_bounds = {k: (-pi, pi) for k in bus_attrs['va']}
    libbus.declare_var_va(model,
                          bus_attrs['names'],
                          initialize=bus_attrs['va'],
                          bounds=va_bounds)

    ### include the feasibility slack for the bus balances
    p_rhs_kwargs = {}
    q_rhs_kwargs = {}
    if include_feasibility_slack:
        p_rhs_kwargs, q_rhs_kwargs, penalty_expr = _include_feasibility_slack(
            model, bus_attrs, gen_attrs, bus_p_loads, bus_q_loads)

    ### fix the reference bus
    ref_bus = md.data['system']['reference_bus']
    ref_angle = md.data['system']['reference_bus_angle']
    model.va[ref_bus].fix(radians(ref_angle))

    ### declare the generator real and reactive power
    pg_init = {
        k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0
        for k in gen_attrs['pg']
    }
    libgen.declare_var_pg(model,
                          gen_attrs['names'],
                          initialize=pg_init,
                          bounds=zip_items(gen_attrs['p_min'],
                                           gen_attrs['p_max']))

    qg_init = {
        k: (gen_attrs['q_min'][k] + gen_attrs['q_max'][k]) / 2.0
        for k in gen_attrs['qg']
    }
    libgen.declare_var_qg(model,
                          gen_attrs['names'],
                          initialize=qg_init,
                          bounds=zip_items(gen_attrs['q_min'],
                                           gen_attrs['q_max']))

    ### declare the current flows in the branches
    vr_init = {
        k: bus_attrs['vm'][k] * pe.cos(bus_attrs['va'][k])
        for k in bus_attrs['vm']
    }
    vj_init = {
        k: bus_attrs['vm'][k] * pe.sin(bus_attrs['va'][k])
        for k in bus_attrs['vm']
    }
    s_max = {k: branches[k]['rating_long_term'] for k in branches.keys()}
    s_lbub = dict()
    for k in branches.keys():
        if s_max[k] is None:
            s_lbub[k] = (None, None)
        else:
            s_lbub[k] = (-s_max[k], s_max[k])
    pf_bounds = s_lbub
    pt_bounds = s_lbub
    qf_bounds = s_lbub
    qt_bounds = s_lbub
    pf_init = dict()
    pt_init = dict()
    qf_init = dict()
    qt_init = dict()
    for branch_name, branch in branches.items():
        from_bus = branch['from_bus']
        to_bus = branch['to_bus']
        y_matrix = tx_calc.calculate_y_matrix_from_branch(branch)
        ifr_init = tx_calc.calculate_ifr(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        ifj_init = tx_calc.calculate_ifj(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        itr_init = tx_calc.calculate_itr(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        itj_init = tx_calc.calculate_itj(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        pf_init[branch_name] = tx_calc.calculate_p(ifr_init, ifj_init,
                                                   vr_init[from_bus],
                                                   vj_init[from_bus])
        pt_init[branch_name] = tx_calc.calculate_p(itr_init, itj_init,
                                                   vr_init[to_bus],
                                                   vj_init[to_bus])
        qf_init[branch_name] = tx_calc.calculate_q(ifr_init, ifj_init,
                                                   vr_init[from_bus],
                                                   vj_init[from_bus])
        qt_init[branch_name] = tx_calc.calculate_q(itr_init, itj_init,
                                                   vr_init[to_bus],
                                                   vj_init[to_bus])

    libbranch.declare_var_pf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pf_init,
                             bounds=pf_bounds)
    libbranch.declare_var_pt(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pt_init,
                             bounds=pt_bounds)
    libbranch.declare_var_qf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=qf_init,
                             bounds=qf_bounds)
    libbranch.declare_var_qt(model=model,
                             index_set=branch_attrs['names'],
                             initialize=qt_init,
                             bounds=qt_bounds)

    ### declare the branch power flow constraints
    bus_pairs = zip_items(branch_attrs['from_bus'], branch_attrs['to_bus'])
    unique_bus_pairs = list(
        OrderedDict((val, None) for idx, val in bus_pairs.items()).keys())
    libbranch.declare_expr_c(model=model,
                             index_set=unique_bus_pairs,
                             coordinate_type=CoordinateType.POLAR)
    libbranch.declare_expr_s(model=model,
                             index_set=unique_bus_pairs,
                             coordinate_type=CoordinateType.POLAR)
    libbranch.declare_eq_branch_power(model=model,
                                      index_set=branch_attrs['names'],
                                      branches=branches)

    ### declare the pq balances
    libbus.declare_eq_p_balance(model=model,
                                index_set=bus_attrs['names'],
                                bus_p_loads=bus_p_loads,
                                gens_by_bus=gens_by_bus,
                                bus_gs_fixed_shunts=bus_gs_fixed_shunts,
                                inlet_branches_by_bus=inlet_branches_by_bus,
                                outlet_branches_by_bus=outlet_branches_by_bus,
                                **p_rhs_kwargs)

    libbus.declare_eq_q_balance(model=model,
                                index_set=bus_attrs['names'],
                                bus_q_loads=bus_q_loads,
                                gens_by_bus=gens_by_bus,
                                bus_bs_fixed_shunts=bus_bs_fixed_shunts,
                                inlet_branches_by_bus=inlet_branches_by_bus,
                                outlet_branches_by_bus=outlet_branches_by_bus,
                                **q_rhs_kwargs)

    ### declare the thermal limits
    libbranch.declare_ineq_s_branch_thermal_limit(
        model=model,
        index_set=branch_attrs['names'],
        branches=branches,
        s_thermal_limits=s_max,
        flow_type=FlowType.POWER)

    ### declare the voltage min and max inequalities
    libbus.declare_ineq_vm_bus_lbub(model=model,
                                    index_set=bus_attrs['names'],
                                    buses=buses,
                                    coordinate_type=CoordinateType.POLAR)

    ### declare angle difference limits on interconnected buses
    libbranch.declare_ineq_angle_diff_branch_lbub(
        model=model,
        index_set=branch_attrs['names'],
        branches=branches,
        coordinate_type=CoordinateType.POLAR)

    ### declare the generator cost objective
    libgen.declare_expression_pgqg_operating_cost(model=model,
                                                  index_set=gen_attrs['names'],
                                                  p_costs=gen_attrs['p_cost'],
                                                  q_costs=gen_attrs.get(
                                                      'q_cost', None))

    obj_expr = sum(model.pg_operating_cost[gen_name]
                   for gen_name in model.pg_operating_cost)
    if include_feasibility_slack:
        obj_expr += penalty_expr
    if hasattr(model, 'qg_operating_cost'):
        obj_expr += sum(model.qg_operating_cost[gen_name]
                        for gen_name in model.qg_operating_cost)

    model.obj = pe.Objective(expr=obj_expr)

    return model, md
Beispiel #8
0
def create_ptdf_dcopf_model(model_data, include_feasibility_slack=False,base_point=BasePointType.FLATSTART):
    md = model_data.clone_in_service()
    tx_utils.scale_ModelData_to_pu(md, inplace = True)

    data_utils.create_dicts_of_ptdf(md,base_point=base_point)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    gen_attrs = md.attributes(element_type='generator')
    bus_attrs = md.attributes(element_type='bus')
    branch_attrs = md.attributes(element_type='branch')
    load_attrs = md.attributes(element_type='load')
    shunt_attrs = md.attributes(element_type='shunt')

    inlet_branches_by_bus, outlet_branches_by_bus = \
        tx_utils.inlet_outlet_branches_by_bus(branches, buses)
    gens_by_bus = tx_utils.gens_by_bus(buses, gens)

    model = pe.ConcreteModel()

    ### declare (and fix) the loads at the buses
    bus_p_loads, _ = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads)
    model.pl.fix()

    ### declare the fixed shunts at the buses
    _, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(buses, shunts)

    ### declare the generator real power
    pg_init = {k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0 for k in gen_attrs['pg']}
    libgen.declare_var_pg(model, gen_attrs['names'], initialize=pg_init,
                          bounds=zip_items(gen_attrs['p_min'], gen_attrs['p_max'])
                          )

    ### include the feasibility slack for the system balance
    p_rhs_kwargs = {}
    if include_feasibility_slack:
        p_rhs_kwargs, penalty_expr = _include_system_feasibility_slack(model, gen_attrs, bus_p_loads)

    ### declare the current flows in the branches
    vr_init = {k: bus_attrs['vm'][k] * pe.cos(bus_attrs['va'][k]) for k in bus_attrs['vm']}
    vj_init = {k: bus_attrs['vm'][k] * pe.sin(bus_attrs['va'][k]) for k in bus_attrs['vm']}
    p_max = {k: branches[k]['rating_long_term'] for k in branches.keys()}
    p_lbub = {k: (-p_max[k],p_max[k]) for k in branches.keys()}
    pf_bounds = p_lbub
    pf_init = dict()
    for branch_name, branch in branches.items():
        from_bus = branch['from_bus']
        to_bus = branch['to_bus']
        y_matrix = tx_calc.calculate_y_matrix_from_branch(branch)
        ifr_init = tx_calc.calculate_ifr(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        ifj_init = tx_calc.calculate_ifj(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        pf_init[branch_name] = tx_calc.calculate_p(ifr_init, ifj_init, vr_init[from_bus], vj_init[from_bus])

    libbranch.declare_var_pf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pf_init,
                             bounds=pf_bounds
                             )

    ### declare the branch power flow approximation constraints
    libbranch.declare_eq_branch_power_ptdf_approx(model=model,
                                                  index_set=branch_attrs['names'],
                                                  branches=branches,
                                                  buses=buses,
                                                  bus_p_loads=bus_p_loads,
                                                  gens_by_bus=gens_by_bus,
                                                  bus_gs_fixed_shunts=bus_gs_fixed_shunts
                                                  )

    ### declare the p balance
    libbus.declare_eq_p_balance_ed(model=model,
                                   index_set=bus_attrs['names'],
                                   bus_p_loads=bus_p_loads,
                                   gens_by_bus=gens_by_bus,
                                   bus_gs_fixed_shunts=bus_gs_fixed_shunts,
                                   **p_rhs_kwargs
                                   )

    ### declare the real power flow limits
    libbranch.declare_ineq_p_branch_thermal_lbub(model=model,
                                                 index_set=branch_attrs['names'],
                                                 branches=branches,
                                                 p_thermal_limits=p_max,
                                                 approximation_type=ApproximationType.PTDF
                                                 )

    ### declare the generator cost objective
    libgen.declare_expression_pgqg_operating_cost(model=model,
                                                  index_set=gen_attrs['names'],
                                                  p_costs=gen_attrs['p_cost']
                                                  )

    obj_expr = sum(model.pg_operating_cost[gen_name] for gen_name in model.pg_operating_cost)
    if include_feasibility_slack:
        obj_expr += penalty_expr

    model.obj = pe.Objective(expr=obj_expr)

    return model, md
Beispiel #9
0
def _btheta_dcopf_network_model(block, tm):
    m = block.model()

    buses = m._buses
    branches = m._branches

    branches_in_service = tuple(l for l in m.TransmissionLines
                                if not value(m.LineOutOfService[l, tm]))
    ## this will serve as a key into our dict of PTDF matricies,
    ## so that we can avoid recalculating them each time step
    ## with the same network topology
    branches_out_service = tuple(l for l in m.TransmissionLines
                                 if value(m.LineOutOfService[l, tm]))

    ## need the inlet/outlet relationship given some lines may be out
    inlet_branches_by_bus = dict()
    outlet_branches_by_bus = dict()
    for b in m.Buses:
        inlet_branches_by_bus[b] = list()
        for l in m.LinesTo[b]:
            if l not in branches_out_service:
                inlet_branches_by_bus[b].append(l)
        outlet_branches_by_bus[b] = list()
        for l in m.LinesFrom[b]:
            if l not in branches_out_service:
                outlet_branches_by_bus[b].append(l)

    ## this is not the "real" gens by bus, but the
    ## index of net injections from the UC model
    gens_by_bus = block.gens_by_bus

    ### declare (and fix) the loads at the buses
    bus_p_loads = {b: value(m.Demand[b, tm]) for b in m.Buses}

    libbus.declare_var_pl(block, buses.keys(), initialize=bus_p_loads)
    block.pl.fix()

    ### get the fixed shunts at the buses
    bus_gs_fixed_shunts = m._bus_gs_fixed_shunts

    ### declare the polar voltages
    va_bounds = {k: (-pi, pi) for k in buses.keys()}
    libbus.declare_var_va(block,
                          buses.keys(),
                          initialize=None,
                          bounds=va_bounds)

    ### fix the reference bus
    ref_bus = value(m.ReferenceBus)
    ref_angle = value(m.ReferenceBusAngle)
    block.va[ref_bus].fix(math.radians(ref_angle))

    p_max = {k: branches[k]['rating_long_term'] for k in branches_in_service}
    p_lbub = {k: (-p_max[k], p_max[k]) for k in branches_in_service}
    pf_bounds = p_lbub

    libbranch.declare_var_pf(model=block,
                             index_set=branches_in_service,
                             initialize=None,
                             bounds=pf_bounds)

    ### declare the branch power flow approximation constraints
    libbranch.declare_eq_branch_power_btheta_approx(
        model=block, index_set=branches_in_service, branches=branches)

    ### declare the p balance
    libbus.declare_eq_p_balance_dc_approx(
        model=block,
        index_set=buses.keys(),
        bus_p_loads=bus_p_loads,
        gens_by_bus=gens_by_bus,
        bus_gs_fixed_shunts=bus_gs_fixed_shunts,
        inlet_branches_by_bus=inlet_branches_by_bus,
        outlet_branches_by_bus=outlet_branches_by_bus,
        approximation_type=ApproximationType.BTHETA)

    ### declare the real power flow limits
    libbranch.declare_ineq_p_branch_thermal_lbub(
        model=block,
        index_set=branches_in_service,
        branches=branches,
        p_thermal_limits=p_max,
        approximation_type=ApproximationType.BTHETA)

    ### declare angle difference limits on interconnected buses
    libbranch.declare_ineq_angle_diff_branch_lbub(
        model=block,
        index_set=branches_in_service,
        branches=branches,
        coordinate_type=CoordinateType.POLAR)

    return block
Beispiel #10
0
def create_socp_acopf_model(model_data, include_feasibility_slack=False):
    md = model_data.clone_in_service()
    tx_utils.scale_ModelData_to_pu(md, inplace = True)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    gen_attrs = md.attributes(element_type='generator')
    bus_attrs = md.attributes(element_type='bus')
    branch_attrs = md.attributes(element_type='branch')
    load_attrs = md.attributes(element_type='load')
    shunt_attrs = md.attributes(element_type='shunt')

    inlet_branches_by_bus, outlet_branches_by_bus = \
        tx_utils.inlet_outlet_branches_by_bus(branches, buses)
    gens_by_bus = tx_utils.gens_by_bus(buses, gens)

    model = pe.ConcreteModel()

    ### declare (and fix) the loads at the buses
    bus_p_loads, bus_q_loads = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads)
    libbus.declare_var_ql(model, bus_attrs['names'], initialize=bus_q_loads)
    model.pl.fix()
    model.ql.fix()

    ### declare the fixed shunts at the buses
    bus_bs_fixed_shunts, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(buses, shunts)


    ### declare the rectangular voltages
    neg_v_max = map_items(op.neg, bus_attrs['v_max'])
    vr_init = {k: bus_attrs['vm'][k] * pe.cos(bus_attrs['va'][k]) for k in bus_attrs['vm']}
    # libbus.declare_var_vr(model, bus_attrs['names'], initialize=vr_init,
    #                       bounds=zip_items(neg_v_max, bus_attrs['v_max'])
    #                       )

    vj_init = {k: bus_attrs['vm'][k] * pe.sin(bus_attrs['va'][k]) for k in bus_attrs['vm']}
    # libbus.declare_var_vj(model, bus_attrs['names'], initialize=vj_init,
    #                       bounds=zip_items(neg_v_max, bus_attrs['v_max'])
    #                       )


    # w variable for socp
    vj2_init = {k: (bus_attrs['vm'][k] * pe.sin(bus_attrs['va'][k]))**2 for k in bus_attrs['vm']}
    vr2_init = {k: (bus_attrs['vm'][k] * pe.cos(bus_attrs['va'][k]))**2 for k in bus_attrs['vm']}
    w_init = {k: vr2_init[k]+vj2_init[k] for k in vj2_init}
    wub = {k:bus_attrs['v_max'][k]**2 for k in bus_attrs['v_max']}
    wlb = {k:bus_attrs['v_min'][k]**2 for k in bus_attrs['v_min']}
    ## v_min**2 <= w <= v_max**2
    libbus.declare_var_w(model, bus_attrs['names'], initialize = w_init, 
                        bounds =zip_items(wlb,wub))



    ### include the feasibility slack for the bus balances
    p_rhs_kwargs = {}
    q_rhs_kwargs = {}
    if include_feasibility_slack:
        p_rhs_kwargs, q_rhs_kwargs, penalty_expr = _include_feasibility_slack(model, bus_attrs, gen_attrs, bus_p_loads, bus_q_loads)

    ### fix the reference bus
    # ref_bus = md.data['system']['reference_bus']
    # ref_angle = md.data['system']['reference_bus_angle']
    # if ref_angle != 0.0:
    #     libbus.declare_eq_ref_bus_nonzero(model, ref_angle, ref_bus)
    # else:
    #     model.vj[ref_bus].fix(0.0)
    #     model.vr[ref_bus].setlb(0.0)

    ### declare the generator real and reactive power
    pg_init = {k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0 for k in gen_attrs['pg']}
    libgen.declare_var_pg(model, gen_attrs['names'], initialize=pg_init,
                          bounds=zip_items(gen_attrs['p_min'], gen_attrs['p_max'])
                          )

    qg_init = {k: (gen_attrs['q_min'][k] + gen_attrs['q_max'][k]) / 2.0 for k in gen_attrs['qg']}
    libgen.declare_var_qg(model, gen_attrs['names'], initialize=qg_init,
                          bounds=zip_items(gen_attrs['q_min'], gen_attrs['q_max'])
                          )

    ### declare the current flows in the branches
    s_max = {k: branches[k]['rating_long_term'] for k in branches.keys()}
    s_lbub = dict()
    for k in branches.keys():
        if s_max[k] is None:
            s_lbub[k] = (None, None)
        else:
            s_lbub[k] = (-s_max[k],s_max[k])
    pf_bounds = s_lbub
    pt_bounds = s_lbub
    qf_bounds = s_lbub
    qt_bounds = s_lbub
    pf_init = dict()
    pt_init = dict()
    qf_init = dict()
    qt_init = dict()
    cbk_init = dict()
    sbk_init = dict()
    cbk_bounds = dict()
    sbk_bounds = dict()
    for branch_name, branch in branches.items():
        from_bus = branch['from_bus']
        to_bus = branch['to_bus']
        ba_max = branch['angle_diff_max']
        ba_min = branch['angle_diff_min']
        y_matrix = tx_calc.calculate_y_matrix_from_branch(branch)
        ifr_init = tx_calc.calculate_ifr(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        ifj_init = tx_calc.calculate_ifj(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        itr_init = tx_calc.calculate_itr(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        itj_init = tx_calc.calculate_itj(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        pf_init[branch_name] = tx_calc.calculate_p(ifr_init, ifj_init, vr_init[from_bus], vj_init[from_bus])
        pt_init[branch_name] = tx_calc.calculate_p(itr_init, itj_init, vr_init[to_bus], vj_init[to_bus])
        qf_init[branch_name] = tx_calc.calculate_q(ifr_init, ifj_init, vr_init[from_bus], vj_init[from_bus])
        qt_init[branch_name] = tx_calc.calculate_q(itr_init, itj_init, vr_init[to_bus], vj_init[to_bus])

        #SOCP related variable bounds and init
        cbk_init[from_bus,to_bus] = vr_init[from_bus]*vr_init[to_bus] + vj_init[from_bus]*vj_init[to_bus]
        sbk_init[from_bus,to_bus] = vr_init[from_bus]*vj_init[to_bus] - vr_init[to_bus]*vj_init[from_bus]

        if ba_max is None and ba_min is None:
          cbk_bounds[from_bus,to_bus] = ( bus_attrs['v_min'][from_bus]*bus_attrs['v_min'][to_bus]*min(pe.cos(-math.pi/2),pe.cos(math.pi/2)),
                                      bus_attrs['v_max'][from_bus]*bus_attrs['v_max'][to_bus]*1.0)
          sbk_bounds[from_bus,to_bus] = ( bus_attrs['v_max'][from_bus]*bus_attrs['v_max'][to_bus]*pe.sin(-math.pi/2),
                                      bus_attrs['v_max'][from_bus]*bus_attrs['v_max'][to_bus]*pe.sin(math.pi/2))
        if ba_max > 0 and ba_min < 0:
          cbk_bounds[from_bus,to_bus] = (bus_attrs['v_min'][from_bus]*bus_attrs['v_min'][to_bus]*min(pe.cos(ba_max * math.pi/180),pe.cos(ba_min * math.pi/180)),
                                      bus_attrs['v_max'][from_bus]*bus_attrs['v_max'][to_bus]*1.0)
          sbk_bounds[from_bus,to_bus] = ( bus_attrs['v_max'][from_bus]*bus_attrs['v_max'][to_bus]*pe.sin(ba_min * math.pi/180),
                                      bus_attrs['v_max'][from_bus]*bus_attrs['v_max'][to_bus]*pe.sin(math.pi/2))
        if ba_max <= 0:
          cbk_bounds[from_bus,to_bus] = (bus_attrs['v_min'][from_bus]*bus_attrs['v_min'][to_bus]*pe.cos(ba_min * math.pi/180),
                                      bus_attrs['v_max'][from_bus]*bus_attrs['v_max'][to_bus]*pe.cos(ba_max * math.pi/180))
          sbk_bounds[from_bus,to_bus] = ( bus_attrs['v_max'][from_bus]*bus_attrs['v_max'][to_bus]*pe.sin(ba_min * math.pi/180),
                                      bus_attrs['v_max'][from_bus]*bus_attrs['v_max'][to_bus]*pe.sin(math.pi/2))
        if ba_min >= 0:
          cbk_bounds[from_bus,to_bus] = (bus_attrs['v_min'][from_bus]*bus_attrs['v_min'][to_bus]*pe.cos(ba_max * math.pi/180),
                                      bus_attrs['v_max'][from_bus]*bus_attrs['v_max'][to_bus]*pe.cos(ba_min * math.pi/180))
          sbk_bounds[from_bus,to_bus] = ( bus_attrs['v_max'][from_bus]*bus_attrs['v_max'][to_bus]*pe.sin(ba_min * math.pi/180),
                                      bus_attrs['v_max'][from_bus]*bus_attrs['v_max'][to_bus]*pe.sin(math.pi/2))

    
    #print(bus_attrs)
    #print(branch_attrs)

    libbranch.declare_var_pf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pf_init,
                             bounds=pf_bounds
                             )
    libbranch.declare_var_pt(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pt_init,
                             bounds=pt_bounds
                             )
    libbranch.declare_var_qf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=qf_init,
                             bounds=qf_bounds
                             )
    libbranch.declare_var_qt(model=model,
                             index_set=branch_attrs['names'],
                             initialize=qt_init,
                             bounds=qt_bounds
                             )


    bus_pairs = zip_items(branch_attrs['from_bus'],branch_attrs['to_bus'])
    unique_bus_pairs = list(set([val for idx,val in bus_pairs.items()]))

    libbranch.declare_var_c(model = model,
                             index_set = unique_bus_pairs,
                             initialize = cbk_init,
                             bounds = cbk_bounds
                             )

    libbranch.declare_var_s(model = model,
                             index_set = unique_bus_pairs,
                             initialize = sbk_init,
                             bounds = sbk_bounds
                             )

    ### declare the branch power flow constraints
    libbranch.declare_eq_branch_power_socp(model=model,
                                      index_set=branch_attrs['names'],
                                      branches=branches,
                                      branch_attrs=branch_attrs,
                                      coordinate_type=CoordinateType.RECTANGULAR
                                      )

    ### declare the pq balances
    libbus.declare_eq_p_balance_socp(model=model,
                                index_set=bus_attrs['names'],
                                bus_p_loads=bus_p_loads,
                                gens_by_bus=gens_by_bus,
                                bus_gs_fixed_shunts=bus_gs_fixed_shunts,
                                inlet_branches_by_bus=inlet_branches_by_bus,
                                outlet_branches_by_bus=outlet_branches_by_bus,
                                coordinate_type=CoordinateType.RECTANGULAR,
                                **p_rhs_kwargs
                                )

    libbus.declare_eq_q_balance_socp(model=model,
                                index_set=bus_attrs['names'],
                                bus_q_loads=bus_q_loads,
                                gens_by_bus=gens_by_bus,
                                bus_bs_fixed_shunts=bus_bs_fixed_shunts,
                                inlet_branches_by_bus=inlet_branches_by_bus,
                                outlet_branches_by_bus=outlet_branches_by_bus,
                                coordinate_type=CoordinateType.RECTANGULAR,
                                **q_rhs_kwargs
                                )

    ### declare the thermal limits
    libbranch.declare_ineq_s_branch_thermal_limit(model=model,
                                                  index_set=branch_attrs['names'],
                                                  branches=branches,
                                                  s_thermal_limits=s_max,
                                                  flow_type=FlowType.POWER
                                                  )

    ### declare the voltage min and max inequalities
    # libbus.declare_ineq_vm_bus_lbub(model=model,
    #                                 index_set=bus_attrs['names'],
    #                                 buses=buses,
    #                                 coordinate_type=CoordinateType.RECTANGULAR
    #                                 )

    ### declare angle difference limits on interconnected buses
    # libbranch.declare_ineq_angle_diff_branch_lbub(model=model,
    #                                               index_set=branch_attrs['names'],
    #                                               branches=branches,
    #                                               coordinate_type=CoordinateType.RECTANGULAR
    #                                               )

    libbranch.declare_socp_scw(model = model, index_set = branch_attrs['names'],
                                 branches = branches, 
                                 branch_attrs = branch_attrs)

    ### declare the generator cost objective
    libgen.declare_expression_pgqg_operating_cost(model=model,
                                                  index_set=gen_attrs['names'],
                                                  p_costs=gen_attrs['p_cost'],
                                                  q_costs=gen_attrs.get('q_cost', None)
                                                  )

    obj_expr = sum(model.pg_operating_cost[gen_name] for gen_name in model.pg_operating_cost)
    if include_feasibility_slack:
        obj_expr += penalty_expr
    if hasattr(model, 'qg_operating_cost'):
        obj_expr += sum(model.qg_operating_cost[gen_name] for gen_name in model.qg_operating_cost)

    model.obj = pe.Objective(expr=obj_expr)

    return model, md
Beispiel #11
0
def create_rsv_acopf_model(model_data):
    md = tx_utils.scale_ModelData_to_pu(model_data)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    gen_attrs = md.attributes(element_type='generator')
    bus_attrs = md.attributes(element_type='bus')
    branch_attrs = md.attributes(element_type='branch')
    load_attrs = md.attributes(element_type='load')
    shunt_attrs = md.attributes(element_type='shunt')

    inlet_branches_by_bus, outlet_branches_by_bus = \
        tx_utils.inlet_outlet_branches_by_bus(branches, buses)
    gens_by_bus = tx_utils.gens_in_service_by_bus(buses, gens)

    model = pe.ConcreteModel()

    ### declare (and fix) the loads at the buses
    bus_p_loads, bus_q_loads = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads)
    libbus.declare_var_ql(model, bus_attrs['names'], initialize=bus_q_loads)
    model.pl.fix()
    model.ql.fix()

    ### declare the fixed shunts at the buses
    bus_bs_fixed_shunts, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(
        buses, shunts)

    ### declare the rectangular voltages
    neg_v_max = map_items(op.neg, bus_attrs['v_max'])
    vr_init = {
        k: bus_attrs['vm'][k] * pe.cos(bus_attrs['va'][k])
        for k in bus_attrs['vm']
    }
    libbus.declare_var_vr(model,
                          bus_attrs['names'],
                          initialize=vr_init,
                          bounds=zip_items(neg_v_max, bus_attrs['v_max']))

    vj_init = {
        k: bus_attrs['vm'][k] * pe.sin(bus_attrs['va'][k])
        for k in bus_attrs['vm']
    }
    libbus.declare_var_vj(model,
                          bus_attrs['names'],
                          initialize=vj_init,
                          bounds=zip_items(neg_v_max, bus_attrs['v_max']))

    ### fix the reference bus
    ref_bus = md.data['system']['reference_bus']
    model.vj[ref_bus].fix(0.0)
    model.vr[ref_bus].setlb(0.0)

    ref_angle = md.data['system']['reference_bus_angle']
    if ref_angle != 0.0:
        raise ValueError('The RSV ACOPF formulation currently only supports'
                         ' a reference bus angle of 0 degrees, but an angle'
                         ' of {} degrees was found.'.format(ref_angle))

    ### declare the generator real and reactive power
    pg_init = {
        k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0
        for k in gen_attrs['pg']
    }
    libgen.declare_var_pg(model,
                          gen_attrs['names'],
                          initialize=pg_init,
                          bounds=zip_items(gen_attrs['p_min'],
                                           gen_attrs['p_max']))

    qg_init = {
        k: (gen_attrs['q_min'][k] + gen_attrs['q_max'][k]) / 2.0
        for k in gen_attrs['qg']
    }
    libgen.declare_var_qg(model,
                          gen_attrs['names'],
                          initialize=qg_init,
                          bounds=zip_items(gen_attrs['q_min'],
                                           gen_attrs['q_max']))

    ### declare the current flows in the branches
    s_max = {k: branches[k]['rating_long_term'] for k in branches.keys()}
    s_lbub = {k: (-s_max[k], s_max[k]) for k in branches.keys()}
    pf_bounds = s_lbub
    pt_bounds = s_lbub
    qf_bounds = s_lbub
    qt_bounds = s_lbub
    pf_init = dict()
    pt_init = dict()
    qf_init = dict()
    qt_init = dict()
    for branch_name, branch in branches.items():
        from_bus = branch['from_bus']
        to_bus = branch['to_bus']
        y_matrix = tx_calc.calculate_y_matrix_from_branch(branch)
        ifr_init = tx_calc.calculate_ifr(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        ifj_init = tx_calc.calculate_ifj(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        itr_init = tx_calc.calculate_itr(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        itj_init = tx_calc.calculate_itj(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        pf_init[branch_name] = tx_calc.calculate_p(ifr_init, ifj_init,
                                                   vr_init[from_bus],
                                                   vj_init[from_bus])
        pt_init[branch_name] = tx_calc.calculate_p(itr_init, itj_init,
                                                   vr_init[to_bus],
                                                   vj_init[to_bus])
        qf_init[branch_name] = tx_calc.calculate_q(ifr_init, ifj_init,
                                                   vr_init[from_bus],
                                                   vj_init[from_bus])
        qt_init[branch_name] = tx_calc.calculate_q(itr_init, itj_init,
                                                   vr_init[to_bus],
                                                   vj_init[to_bus])

    libbranch.declare_var_pf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pf_init,
                             bounds=pf_bounds)
    libbranch.declare_var_pt(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pt_init,
                             bounds=pt_bounds)
    libbranch.declare_var_qf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=qf_init,
                             bounds=qf_bounds)
    libbranch.declare_var_qt(model=model,
                             index_set=branch_attrs['names'],
                             initialize=qt_init,
                             bounds=qt_bounds)

    ### declare the branch power flow constraints
    libbranch.declare_eq_branch_power(
        model=model,
        index_set=branch_attrs['names'],
        branches=branches,
        branch_attrs=branch_attrs,
        coordinate_type=CoordinateType.RECTANGULAR)

    ### declare the pq balances
    libbus.declare_eq_p_balance(model=model,
                                index_set=bus_attrs['names'],
                                bus_p_loads=bus_p_loads,
                                gens_by_bus=gens_by_bus,
                                bus_gs_fixed_shunts=bus_gs_fixed_shunts,
                                inlet_branches_by_bus=inlet_branches_by_bus,
                                outlet_branches_by_bus=outlet_branches_by_bus,
                                coordinate_type=CoordinateType.RECTANGULAR)

    libbus.declare_eq_q_balance(model=model,
                                index_set=bus_attrs['names'],
                                bus_q_loads=bus_q_loads,
                                gens_by_bus=gens_by_bus,
                                bus_bs_fixed_shunts=bus_bs_fixed_shunts,
                                inlet_branches_by_bus=inlet_branches_by_bus,
                                outlet_branches_by_bus=outlet_branches_by_bus,
                                coordinate_type=CoordinateType.RECTANGULAR)

    ### declare the thermal limits
    libbranch.declare_ineq_s_branch_thermal_limit(
        model=model,
        index_set=branch_attrs['names'],
        branches=branches,
        s_thermal_limits=s_max,
        flow_type=FlowType.POWER)

    ### declare the voltage min and max inequalities
    libbus.declare_ineq_vm_bus_lbub(model=model,
                                    index_set=bus_attrs['names'],
                                    buses=buses,
                                    coordinate_type=CoordinateType.RECTANGULAR)

    ### declare angle difference limits on interconnected buses
    libbranch.declare_ineq_angle_diff_branch_lbub(
        model=model,
        index_set=branch_attrs['names'],
        branches=branches,
        coordinate_type=CoordinateType.RECTANGULAR)

    ### declare the generator cost objective
    libgen.declare_expression_pgqg_operating_cost(model=model,
                                                  index_set=gen_attrs['names'],
                                                  p_costs=gen_attrs['p_cost'],
                                                  q_costs=gen_attrs.get(
                                                      'q_cost', None))

    obj_expr = sum(model.pg_operating_cost[gen_name]
                   for gen_name in model.pg_operating_cost)
    if hasattr(model, 'qg_operating_cost'):
        obj_expr += sum(model.qg_operating_cost[gen_name]
                        for gen_name in model.qg_operating_cost)

    model.obj = pe.Objective(expr=obj_expr)

    return model
Beispiel #12
0
def create_btheta_dcopf_model(model_data, include_angle_diff_limits=False, include_feasibility_slack=False, pw_cost_model='delta'):
    md = model_data.clone_in_service()
    tx_utils.scale_ModelData_to_pu(md, inplace = True)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    dc_branches = dict(md.elements(element_type='dc_branch'))

    gen_attrs = md.attributes(element_type='generator')
    bus_attrs = md.attributes(element_type='bus')
    branch_attrs = md.attributes(element_type='branch')

    inlet_branches_by_bus, outlet_branches_by_bus = \
        tx_utils.inlet_outlet_branches_by_bus(branches, buses)
    gens_by_bus = tx_utils.gens_by_bus(buses, gens)

    model = pe.ConcreteModel()

    ### declare (and fix) the loads at the buses
    bus_p_loads, _ = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads)
    model.pl.fix()

    ### declare the fixed shunts at the buses
    _, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(buses, shunts)

    ### declare the polar voltages
    va_bounds = {k: (-pi, pi) for k in bus_attrs['va']}
    libbus.declare_var_va(model, bus_attrs['names'],
                          initialize=tx_utils.radians_from_degrees_dict(bus_attrs['va']),
                          bounds=va_bounds
                          )

    ### include the feasibility slack for the bus balances
    p_rhs_kwargs = {}
    penalty_expr = None
    if include_feasibility_slack:
        p_marginal_slack_penalty = _validate_and_extract_slack_penalty(md)        
        p_rhs_kwargs, penalty_expr = _include_feasibility_slack(model, bus_attrs['names'], bus_p_loads,
                                                                gens_by_bus, gen_attrs, p_marginal_slack_penalty)

    ### fix the reference bus
    ref_bus = md.data['system']['reference_bus']
    ref_angle = md.data['system']['reference_bus_angle']
    model.va[ref_bus].fix(radians(ref_angle))

    ### declare the generator real power
    pg_init = {k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0 for k in gen_attrs['pg']}
    libgen.declare_var_pg(model, gen_attrs['names'], initialize=pg_init,
                          bounds=zip_items(gen_attrs['p_min'], gen_attrs['p_max'])
                          )

    ### declare the current flows in the branches
    vr_init = {k: bus_attrs['vm'][k] * pe.cos(radians(bus_attrs['va'][k])) for k in bus_attrs['vm']}
    vj_init = {k: bus_attrs['vm'][k] * pe.sin(radians(bus_attrs['va'][k])) for k in bus_attrs['vm']}
    p_max = {k: branches[k]['rating_long_term'] for k in branches.keys()}
    p_lbub = dict()
    for k in branches.keys():
        k_pmax = p_max[k]
        if k_pmax is None:
            p_lbub[k] = (None, None)
        else:
            p_lbub[k] = (-k_pmax,k_pmax)
    pf_bounds = p_lbub
    pf_init = dict()
    for branch_name, branch in branches.items():
        from_bus = branch['from_bus']
        to_bus = branch['to_bus']
        y_matrix = tx_calc.calculate_y_matrix_from_branch(branch)
        ifr_init = tx_calc.calculate_ifr(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        ifj_init = tx_calc.calculate_ifj(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        pf_init[branch_name] = tx_calc.calculate_p(ifr_init, ifj_init, vr_init[from_bus], vj_init[from_bus])

    libbranch.declare_var_pf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pf_init,
                             bounds=pf_bounds
                             )

    if dc_branches:
        dcpf_bounds = dict()
        for k, k_dict in dc_branches.items():
            kp_max = k_dict['rating_long_term']
            if kp_max is None:
                dcpf_bounds[k] = (None, None)
            else:
                dcpf_bounds[k] = (-kp_max, kp_max)
        libbranch.declare_var_dcpf(model=model,
                                   index_set=dc_branches.keys(),
                                   initialize=0.,
                                   bounds=dcpf_bounds,
                                  )
        dc_inlet_branches_by_bus, dc_outlet_branches_by_bus = \
                tx_utils.inlet_outlet_branches_by_bus(dc_branches, buses)
    else:
        dc_inlet_branches_by_bus = None
        dc_outlet_branches_by_bus = None


    ### declare the branch power flow approximation constraints
    libbranch.declare_eq_branch_power_btheta_approx(model=model,
                                                    index_set=branch_attrs['names'],
                                                    branches=branches
                                                    )

    ### declare the p balance
    libbus.declare_eq_p_balance_dc_approx(model=model,
                                          index_set=bus_attrs['names'],
                                          bus_p_loads=bus_p_loads,
                                          gens_by_bus=gens_by_bus,
                                          bus_gs_fixed_shunts=bus_gs_fixed_shunts,
                                          inlet_branches_by_bus=inlet_branches_by_bus,
                                          outlet_branches_by_bus=outlet_branches_by_bus,
                                          approximation_type=ApproximationType.BTHETA,
                                          dc_inlet_branches_by_bus=dc_inlet_branches_by_bus,
                                          dc_outlet_branches_by_bus=dc_outlet_branches_by_bus,
                                          **p_rhs_kwargs
                                          )

    ### declare the real power flow limits
    libbranch.declare_ineq_p_branch_thermal_lbub(model=model,
                                                 index_set=branch_attrs['names'],
                                                 branches=branches,
                                                 p_thermal_limits=p_max,
                                                 approximation_type=ApproximationType.BTHETA
                                                 )

    ### declare angle difference limits on interconnected buses
    if include_angle_diff_limits:
        libbranch.declare_ineq_angle_diff_branch_lbub(model=model,
                                                      index_set=branch_attrs['names'],
                                                      branches=branches,
                                                      coordinate_type=CoordinateType.POLAR
                                                      )

    # declare the generator cost objective
    p_costs = gen_attrs['p_cost']
    pw_pg_cost_gens = list(libgen.pw_gen_generator(gen_attrs['names'], costs=p_costs))
    if len(pw_pg_cost_gens) > 0:
        if pw_cost_model == 'delta':
            libgen.declare_var_delta_pg(model=model, index_set=pw_pg_cost_gens, p_costs=p_costs)
            libgen.declare_pg_delta_pg_con(model=model, index_set=pw_pg_cost_gens, p_costs=p_costs)
        else:
            libgen.declare_var_pg_cost(model=model, index_set=pw_pg_cost_gens, p_costs=p_costs)
            libgen.declare_piecewise_pg_cost_cons(model=model, index_set=pw_pg_cost_gens, p_costs=p_costs)
    libgen.declare_expression_pg_operating_cost(model=model, index_set=gen_attrs['names'], p_costs=p_costs, pw_formulation=pw_cost_model)
    obj_expr = sum(model.pg_operating_cost[gen_name] for gen_name in model.pg_operating_cost)

    if include_feasibility_slack:
        obj_expr += penalty_expr

    model.obj = pe.Objective(expr=obj_expr)

    return model, md
Beispiel #13
0
def _create_base_acpf_model(model_data):
    md = model_data.clone_in_service()
    tx_utils.scale_ModelData_to_pu(md, inplace = True)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    gen_attrs = md.attributes(element_type='generator')
    bus_attrs = md.attributes(element_type='bus')
    branch_attrs = md.attributes(element_type='branch')
    inlet_branches_by_bus, outlet_branches_by_bus = \
        tx_utils.inlet_outlet_branches_by_bus(branches, buses)
    gens_by_bus = tx_utils.gens_by_bus(buses, gens)

    bus_pairs = zip_items(branch_attrs['from_bus'], branch_attrs['to_bus'])
    unique_bus_pairs = list(OrderedDict((val, None) for idx, val in bus_pairs.items()))

    model = pe.ConcreteModel()

    ### declare (and fix) the loads at the buses
    bus_p_loads, bus_q_loads = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads)
    libbus.declare_var_ql(model, bus_attrs['names'], initialize=bus_q_loads)
    model.pl.fix()
    model.ql.fix()

    ### declare the fixed shunts at the buses
    bus_bs_fixed_shunts, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(buses, shunts)

    libbus.declare_var_vmsq(model=model,
                            index_set=bus_attrs['names'],
                            initialize={k: v**2 for k, v in bus_attrs['vm'].items()}
                            )
    libbranch.declare_var_c(model=model, index_set=unique_bus_pairs)
    libbranch.declare_var_s(model=model, index_set=unique_bus_pairs)

    ### declare the generator real and reactive power
    #pg_init = {k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0 for k in gen_attrs['pg']}
    libgen.declare_var_pg(model, gen_attrs['names'], initialize=gen_attrs['pg'])

    #qg_init = {k: (gen_attrs['q_min'][k] + gen_attrs['q_max'][k]) / 2.0 for k in gen_attrs['qg']}
    libgen.declare_var_qg(model, gen_attrs['names'], initialize=gen_attrs['qg'])

    ### declare the current flows in the branches
    vr_init = {k: bus_attrs['vm'][k] * pe.cos(radians(bus_attrs['va'][k])) for k in bus_attrs['vm']}
    vj_init = {k: bus_attrs['vm'][k] * pe.sin(radians(bus_attrs['va'][k])) for k in bus_attrs['vm']}
    pf_init = dict()
    pt_init = dict()
    qf_init = dict()
    qt_init = dict()
    for branch_name, branch in branches.items():
        from_bus = branch['from_bus']
        to_bus = branch['to_bus']
        y_matrix = tx_calc.calculate_y_matrix_from_branch(branch)
        ifr_init = tx_calc.calculate_ifr(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        ifj_init = tx_calc.calculate_ifj(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        itr_init = tx_calc.calculate_itr(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        itj_init = tx_calc.calculate_itj(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        pf_init[branch_name] = tx_calc.calculate_p(ifr_init, ifj_init, vr_init[from_bus], vj_init[from_bus])
        pt_init[branch_name] = tx_calc.calculate_p(itr_init, itj_init, vr_init[to_bus], vj_init[to_bus])
        qf_init[branch_name] = tx_calc.calculate_q(ifr_init, ifj_init, vr_init[from_bus], vj_init[from_bus])
        qt_init[branch_name] = tx_calc.calculate_q(itr_init, itj_init, vr_init[to_bus], vj_init[to_bus])

    libbranch.declare_var_pf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pf_init
                             )
    libbranch.declare_var_pt(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pt_init
                             )
    libbranch.declare_var_qf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=qf_init
                             )
    libbranch.declare_var_qt(model=model,
                             index_set=branch_attrs['names'],
                             initialize=qt_init
                             )

    ### declare the branch power flow constraints
    libbranch.declare_eq_branch_power(model=model,
                                      index_set=branch_attrs['names'],
                                      branches=branches
                                      )

    ### declare the pq balances
    libbus.declare_eq_p_balance(model=model,
                                index_set=bus_attrs['names'],
                                bus_p_loads=bus_p_loads,
                                gens_by_bus=gens_by_bus,
                                bus_gs_fixed_shunts=bus_gs_fixed_shunts,
                                inlet_branches_by_bus=inlet_branches_by_bus,
                                outlet_branches_by_bus=outlet_branches_by_bus
                                )

    libbus.declare_eq_q_balance(model=model,
                                index_set=bus_attrs['names'],
                                bus_q_loads=bus_q_loads,
                                gens_by_bus=gens_by_bus,
                                bus_bs_fixed_shunts=bus_bs_fixed_shunts,
                                inlet_branches_by_bus=inlet_branches_by_bus,
                                outlet_branches_by_bus=outlet_branches_by_bus
                                )

    # if there are multiple generators at the same bus, we will
    # have unwanted degrees of freedom in qg
    # therefore, we add a constraint making them equal
    # if the reference bus has multiple generators, we will also
    # have unwanted degrees of freedom in pg
    #ref_bus = md.data['system']['reference_bus']
    qg_equality_tuples = list()
    #pg_equality_tuples = list()
    for b, genlist in gens_by_bus.items():
        if len(genlist) > 1:
            # we have more than one generator at this bus
            for i in range(1,len(genlist)):
                qg_equality_tuples.append((genlist[0], genlist[i]))
    #        if b == ref_bus:
    #            pg_equality_tuples.append((genlist[0], genlist[i]))

    def _qg_equalities(m,i,j):
        return m.qg[i] == m.qg[j]
    model.qg_equalities = pe.Constraint(qg_equality_tuples, rule=_qg_equalities)

    #def _pg_equalities(m,i,j):
    #    return m.pg[i] == m.pg[j]
    #model.pg_equalities = pe.Constraint(pg_equality_tuples, rule=_pg_equalities)

    model.obj = pe.Objective(expr=0.0)
    return model, md
def create_gdp_subproblem(model, model_data, include_angle_diff_limits=False):
    md = model_data
    tx_utils.scale_ModelData_to_pu(md, inplace=True)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    gen_attrs = md.attributes(element_type='generator')
    bus_attrs = md.attributes(element_type='bus')
    branch_attrs = md.attributes(element_type='branch')

    inlet_branches_by_bus, outlet_branches_by_bus = \
        tx_utils.inlet_outlet_branches_by_bus(branches, buses)
    gens_by_bus = tx_utils.gens_by_bus(buses, gens)

    model.subproblem = bi.SubModel(fixed=(model.u, model.v, model.w))

    ### declare (and fix) the loads at the buses
    bus_p_loads, _ = tx_utils.dict_of_bus_loads(buses, loads)
    buses_with_loads = list(k for k in bus_p_loads.keys()
                            if bus_p_loads[k] != 0.)

    libbus.declare_var_pl(model.subproblem,
                          bus_attrs['names'],
                          initialize=bus_p_loads)
    model.subproblem.pl.fix()

    ### declare the fixed shunts at the buses
    _, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(buses, shunts)

    ### declare the polar voltages
    va_bounds = {k: (-pi, pi) for k in bus_attrs['va']}
    libbus.declare_var_va(model.subproblem,
                          bus_attrs['names'],
                          initialize=tx_utils.radians_from_degrees_dict(
                              bus_attrs['va']),
                          bounds=va_bounds)

    ### fix the reference bus
    ref_bus = md.data['system']['reference_bus']
    ref_angle = md.data['system']['reference_bus_angle']
    model.subproblem.va[ref_bus].fix(radians(ref_angle))

    ### declare the generator real power
    pg_init = {
        k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0
        for k in gen_attrs['pg']
    }
    libgen.declare_var_pg(model.subproblem,
                          gen_attrs['names'],
                          initialize=pg_init,
                          bounds=zip_items(gen_attrs['p_min'],
                                           gen_attrs['p_max']))

    ### declare the current flows in the branches
    vr_init = {
        k: bus_attrs['vm'][k] * pe.cos(radians(bus_attrs['va'][k]))
        for k in bus_attrs['vm']
    }
    vj_init = {
        k: bus_attrs['vm'][k] * pe.sin(radians(bus_attrs['va'][k]))
        for k in bus_attrs['vm']
    }
    p_max = {k: branches[k]['rating_long_term'] for k in branches.keys()}
    p_lbub = {k: (-p_max[k], p_max[k]) for k in branches.keys()}
    pf_bounds = p_lbub
    pf_init = dict()
    for branch_name, branch in branches.items():
        from_bus = branch['from_bus']
        to_bus = branch['to_bus']
        y_matrix = tx_calc.calculate_y_matrix_from_branch(branch)
        ifr_init = tx_calc.calculate_ifr(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        ifj_init = tx_calc.calculate_ifj(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        pf_init[branch_name] = tx_calc.calculate_p(ifr_init, ifj_init,
                                                   vr_init[from_bus],
                                                   vj_init[from_bus])

    libbranch.declare_var_pf(model=model.subproblem,
                             index_set=branch_attrs['names'],
                             initialize=pf_init,
                             bounds=pf_bounds)

    # need to include variable references on subproblem to variables, which exist on the master block
    bi.components.varref(model.subproblem)

    ### declare the branch power flow disjuncts (LHS is status quo, RHS is compromised)
    libbranch.declare_eq_branch_power_btheta_approx(
        model=model.subproblem,
        index_set=branch_attrs['names'],
        branches=branches)
    subcons.declare_eq_branch_power_off(model=model.subproblem,
                                        index_set=branch_attrs['names'],
                                        branches=branches)
    subcons.disjunctify(model=model.subproblem,
                        indicator_name='pf_branch_indicator',
                        disjunct_name='pf_branch_disjunct',
                        LHS_disjunct_set=model.subproblem.eq_pf_branch,
                        RHS_disjunct_set=model.subproblem.eq_pf_branch_off)

    ### declare the load shed disjuncts (LHS is status quo, RHS is compromised)
    subcons.declare_ineq_load_shed_ub(model=model.subproblem,
                                      index_set=buses_with_loads)
    subcons.declare_ineq_load_shed_lb(model=model.subproblem,
                                      index_set=buses_with_loads)
    subcons.declare_ineq_load_shed_lb_off(model=model.subproblem,
                                          index_set=buses_with_loads)
    subcons.disjunctify(
        model=model.subproblem,
        indicator_name='load_shed_indicator',
        disjunct_name='load_shed_disjunct',
        LHS_disjunct_set=model.subproblem.ineq_load_shed_lb,
        RHS_disjunct_set=model.subproblem.ineq_load_shed_lb_off)

    ### declare the generator disjuncts (LHS is status quo, RHS is compromised)
    subcons.declare_ineq_gen_on(model=model.subproblem,
                                index_set=gen_attrs['names'],
                                gens=gens)
    subcons.declare_ineq_gen_off(model=model.subproblem,
                                 index_set=gen_attrs['names'],
                                 gens=gens)
    subcons.disjunctify(model=model.subproblem,
                        indicator_name='gen_indicator',
                        disjunct_name='gen_disjunct',
                        LHS_disjunct_set=model.subproblem.ineq_gen,
                        RHS_disjunct_set=model.subproblem.ineq_gen_off)

    ### declare the p balance
    rhs_kwargs = {'include_feasibility_slack_neg': 'load_shed'}
    libbus.declare_eq_p_balance_dc_approx(
        model=model.subproblem,
        index_set=bus_attrs['names'],
        bus_p_loads=bus_p_loads,
        gens_by_bus=gens_by_bus,
        bus_gs_fixed_shunts=bus_gs_fixed_shunts,
        inlet_branches_by_bus=inlet_branches_by_bus,
        outlet_branches_by_bus=outlet_branches_by_bus,
        approximation_type=ApproximationType.BTHETA,
        **rhs_kwargs)

    ### declare the real power flow limits
    libbranch.declare_ineq_p_branch_thermal_lbub(
        model=model.subproblem,
        index_set=branch_attrs['names'],
        branches=branches,
        p_thermal_limits=p_max,
        approximation_type=ApproximationType.BTHETA)

    ### declare angle difference limits on interconnected buses
    if include_angle_diff_limits:
        libbranch.declare_ineq_angle_diff_branch_lbub(
            model=model.subproblem,
            index_set=branch_attrs['names'],
            branches=branches,
            coordinate_type=CoordinateType.POLAR)

    model.subproblem.obj = pe.Objective(expr=sum(model.load_shed[l]
                                                 for l in buses_with_loads),
                                        sense=pe.minimize)

    return model, md
Beispiel #15
0
def _create_base_power_ac_model(model_data, include_feasibility_slack=False, pw_cost_model='delta'):
    md = model_data.clone_in_service()
    tx_utils.scale_ModelData_to_pu(md, inplace=True)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    gen_attrs = md.attributes(element_type='generator')
    bus_attrs = md.attributes(element_type='bus')
    branch_attrs = md.attributes(element_type='branch')

    inlet_branches_by_bus, outlet_branches_by_bus = \
        tx_utils.inlet_outlet_branches_by_bus(branches, buses)
    gens_by_bus = tx_utils.gens_by_bus(buses, gens)

    bus_pairs = zip_items(branch_attrs['from_bus'], branch_attrs['to_bus'])
    unique_bus_pairs = list(OrderedDict((val, None) for idx, val in bus_pairs.items()))

    model = pe.ConcreteModel()

    ### declare (and fix) the loads at the buses
    bus_p_loads, bus_q_loads = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads)
    libbus.declare_var_ql(model, bus_attrs['names'], initialize=bus_q_loads)
    model.pl.fix()
    model.ql.fix()

    ### declare the fixed shunts at the buses
    bus_bs_fixed_shunts, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(buses, shunts)

    libbus.declare_var_vmsq(model=model,
                            index_set=bus_attrs['names'],
                            initialize={k: v**2 for k, v in bus_attrs['vm'].items()},
                            bounds=zip_items({k: v**2 for k, v in bus_attrs['v_min'].items()},
                                             {k: v**2 for k, v in bus_attrs['v_max'].items()}))
    libbranch.declare_var_c(model=model, index_set=unique_bus_pairs, initialize=1)
    libbranch.declare_var_s(model=model, index_set=unique_bus_pairs, initialize=0)

    ### include the feasibility slack for the bus balances
    p_rhs_kwargs = {}
    q_rhs_kwargs = {}
    if include_feasibility_slack:
        p_marginal_slack_penalty, q_marginal_slack_penalty = _validate_and_extract_slack_penalties(md)
        p_rhs_kwargs, q_rhs_kwargs, penalty_expr = _include_feasibility_slack(model, bus_attrs['names'],
                                                                              bus_p_loads, bus_q_loads,
                                                                              gens_by_bus, gen_attrs,
                                                                              p_marginal_slack_penalty,
                                                                              q_marginal_slack_penalty)

    ### declare the generator real and reactive power
    pg_init = {k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0 for k in gen_attrs['pg']}
    libgen.declare_var_pg(model, gen_attrs['names'], initialize=pg_init,
                          bounds=zip_items(gen_attrs['p_min'], gen_attrs['p_max'])
                          )

    qg_init = {k: (gen_attrs['q_min'][k] + gen_attrs['q_max'][k]) / 2.0 for k in gen_attrs['qg']}
    libgen.declare_var_qg(model, gen_attrs['names'], initialize=qg_init,
                          bounds=zip_items(gen_attrs['q_min'], gen_attrs['q_max'])
                          )

    ### declare the current flows in the branches
    vr_init = {k: bus_attrs['vm'][k] * pe.cos(radians(bus_attrs['va'][k])) for k in bus_attrs['vm']}
    vj_init = {k: bus_attrs['vm'][k] * pe.sin(radians(bus_attrs['va'][k])) for k in bus_attrs['vm']}
    s_max = {k: branches[k]['rating_long_term'] for k in branches.keys()}
    s_lbub = dict()
    for k in branches.keys():
        if s_max[k] is None:
            s_lbub[k] = (None, None)
        else:
            s_lbub[k] = (-s_max[k],s_max[k])
    pf_bounds = s_lbub
    pt_bounds = s_lbub
    qf_bounds = s_lbub
    qt_bounds = s_lbub
    pf_init = dict()
    pt_init = dict()
    qf_init = dict()
    qt_init = dict()
    for branch_name, branch in branches.items():
        from_bus = branch['from_bus']
        to_bus = branch['to_bus']
        y_matrix = tx_calc.calculate_y_matrix_from_branch(branch)
        ifr_init = tx_calc.calculate_ifr(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        ifj_init = tx_calc.calculate_ifj(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        itr_init = tx_calc.calculate_itr(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        itj_init = tx_calc.calculate_itj(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        pf_init[branch_name] = tx_calc.calculate_p(ifr_init, ifj_init, vr_init[from_bus], vj_init[from_bus])
        pt_init[branch_name] = tx_calc.calculate_p(itr_init, itj_init, vr_init[to_bus], vj_init[to_bus])
        qf_init[branch_name] = tx_calc.calculate_q(ifr_init, ifj_init, vr_init[from_bus], vj_init[from_bus])
        qt_init[branch_name] = tx_calc.calculate_q(itr_init, itj_init, vr_init[to_bus], vj_init[to_bus])

    libbranch.declare_var_pf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pf_init,
                             bounds=pf_bounds
                             )
    libbranch.declare_var_pt(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pt_init,
                             bounds=pt_bounds
                             )
    libbranch.declare_var_qf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=qf_init,
                             bounds=qf_bounds
                             )
    libbranch.declare_var_qt(model=model,
                             index_set=branch_attrs['names'],
                             initialize=qt_init,
                             bounds=qt_bounds
                             )

    ### declare the branch power flow constraints
    libbranch.declare_eq_branch_power(model=model,
                                      index_set=branch_attrs['names'],
                                      branches=branches
                                      )

    ### declare the pq balances
    libbus.declare_eq_p_balance(model=model,
                                index_set=bus_attrs['names'],
                                bus_p_loads=bus_p_loads,
                                gens_by_bus=gens_by_bus,
                                bus_gs_fixed_shunts=bus_gs_fixed_shunts,
                                inlet_branches_by_bus=inlet_branches_by_bus,
                                outlet_branches_by_bus=outlet_branches_by_bus,
                                **p_rhs_kwargs
                                )

    libbus.declare_eq_q_balance(model=model,
                                index_set=bus_attrs['names'],
                                bus_q_loads=bus_q_loads,
                                gens_by_bus=gens_by_bus,
                                bus_bs_fixed_shunts=bus_bs_fixed_shunts,
                                inlet_branches_by_bus=inlet_branches_by_bus,
                                outlet_branches_by_bus=outlet_branches_by_bus,
                                **q_rhs_kwargs
                                )

    ### declare the thermal limits
    libbranch.declare_ineq_s_branch_thermal_limit(model=model,
                                                  index_set=branch_attrs['names'],
                                                  branches=branches,
                                                  s_thermal_limits=s_max,
                                                  flow_type=FlowType.POWER
                                                  )

    # declare angle difference limits on interconnected buses
    libbranch.declare_ineq_angle_diff_branch_lbub_c_s(model=model,
                                                      index_set=branch_attrs['names'],
                                                      branches=branches
                                                      )

    # declare the generator cost objective
    p_costs = gen_attrs['p_cost']
    pw_pg_cost_gens = list(libgen.pw_gen_generator(gen_attrs['names'], costs=p_costs))
    if len(pw_pg_cost_gens) > 0:
        if pw_cost_model == 'delta':
            libgen.declare_var_delta_pg(model=model, index_set=pw_pg_cost_gens, p_costs=p_costs)
            libgen.declare_pg_delta_pg_con(model=model, index_set=pw_pg_cost_gens, p_costs=p_costs)
        else:
            libgen.declare_var_pg_cost(model=model, index_set=pw_pg_cost_gens, p_costs=p_costs)
            libgen.declare_piecewise_pg_cost_cons(model=model, index_set=pw_pg_cost_gens, p_costs=p_costs)
    libgen.declare_expression_pg_operating_cost(model=model, index_set=gen_attrs['names'], p_costs=p_costs, pw_formulation=pw_cost_model)
    obj_expr = sum(model.pg_operating_cost[gen_name] for gen_name in model.pg_operating_cost)
    q_costs = gen_attrs.get('q_cost', None)
    if q_costs is not None:
        pw_qg_cost_gens = list(libgen.pw_gen_generator(gen_attrs['names'], costs=q_costs))
        if len(pw_qg_cost_gens) > 0:
            if pw_cost_model == 'delta':
                libgen.declare_var_delta_qg(model=model, index_set=pw_qg_cost_gens, q_costs=q_costs)
                libgen.declare_qg_delta_qg_con(model=model, index_set=pw_qg_cost_gens, q_costs=q_costs)
            else:
                libgen.declare_var_qg_cost(model=model, index_set=pw_qg_cost_gens, q_costs=q_costs)
                libgen.declare_piecewise_qg_cost_cons(model=model, index_set=pw_qg_cost_gens, q_costs=q_costs)
        libgen.declare_expression_qg_operating_cost(model=model, index_set=gen_attrs['names'], q_costs=q_costs, pw_formulation=pw_cost_model)
        obj_expr += sum(model.qg_operating_cost[gen_name] for gen_name in model.qg_operating_cost)

    if include_feasibility_slack:
        obj_expr += penalty_expr

    model.obj = pe.Objective(expr=obj_expr)

    return model, md
Beispiel #16
0
def create_scopf_model(model_data,
                       include_feasibility_slack=False,
                       base_point=BasePointType.FLATSTART,
                       ptdf_options=None):

    ptdf_options = lpu.populate_default_ptdf_options(ptdf_options)

    baseMVA = model_data.data['system']['baseMVA']
    lpu.check_and_scale_ptdf_options(ptdf_options, baseMVA)

    md = model_data.clone_in_service()
    tx_utils.scale_ModelData_to_pu(md, inplace=True)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    dc_branches = dict(md.elements(element_type='dc_branch'))
    contingencies = dict(md.elements(element_type='contingency'))

    gen_attrs = md.attributes(element_type='generator')
    ## to keep things in order
    buses_idx = tuple(buses.keys())
    branches_idx = tuple(branches.keys())

    inlet_branches_by_bus, outlet_branches_by_bus = \
        tx_utils.inlet_outlet_branches_by_bus(branches, buses)
    gens_by_bus = tx_utils.gens_by_bus(buses, gens)

    model = pyo.ConcreteModel()

    ### declare (and fix) the loads at the buses
    bus_p_loads, _ = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(model, buses_idx, initialize=bus_p_loads)
    model.pl.fix()

    ### declare the fixed shunts at the buses
    _, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(buses, shunts)

    ### declare the generator real power
    pg_init = {
        k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0
        for k in gen_attrs['pg']
    }
    libgen.declare_var_pg(model,
                          gen_attrs['names'],
                          initialize=pg_init,
                          bounds=zip_items(gen_attrs['p_min'],
                                           gen_attrs['p_max']))

    ### include the feasibility slack for the system balance
    p_rhs_kwargs = {}
    if include_feasibility_slack:
        p_marginal_slack_penalty = _validate_and_extract_slack_penalty(md)
        p_rhs_kwargs, penalty_expr = _include_system_feasibility_slack(
            model, bus_p_loads, gen_attrs, p_marginal_slack_penalty)

    if dc_branches:
        dcpf_bounds = dict()
        for k, k_dict in dc_branches.items():
            kp_max = k_dict['rating_long_term']
            if kp_max is None:
                dcpf_bounds[k] = (None, None)
            else:
                dcpf_bounds[k] = (-kp_max, kp_max)
        libbranch.declare_var_dcpf(
            model=model,
            index_set=dc_branches.keys(),
            initialize=0.,
            bounds=dcpf_bounds,
        )
        dc_inlet_branches_by_bus, dc_outlet_branches_by_bus = \
                tx_utils.inlet_outlet_branches_by_bus(dc_branches, buses)
    else:
        dc_inlet_branches_by_bus = None
        dc_outlet_branches_by_bus = None

    ### declare the p balance
    libbus.declare_eq_p_balance_ed(model=model,
                                   index_set=buses_idx,
                                   bus_p_loads=bus_p_loads,
                                   gens_by_bus=gens_by_bus,
                                   bus_gs_fixed_shunts=bus_gs_fixed_shunts,
                                   **p_rhs_kwargs)

    ### declare net withdraw expression for use in PTDF power flows
    libbus.declare_expr_p_net_withdraw_at_bus(
        model=model,
        index_set=buses_idx,
        bus_p_loads=bus_p_loads,
        gens_by_bus=gens_by_bus,
        bus_gs_fixed_shunts=bus_gs_fixed_shunts,
        dc_inlet_branches_by_bus=dc_inlet_branches_by_bus,
        dc_outlet_branches_by_bus=dc_outlet_branches_by_bus,
    )

    ### add "blank" power flow expressions
    libbranch.declare_expr_pf(
        model=model,
        index_set=branches_idx,
    )

    ### add "blank" power flow expressions
    model._contingencies = pyo.Set(initialize=contingencies.keys())
    model._branches = pyo.Set(initialize=branches_idx)
    ### NOTE: important that this not be dense, we'll add elements
    ###       as we find violations
    model._contingency_set = pyo.Set(within=model._contingencies *
                                     model._branches)
    model.pfc = pyo.Expression(model._contingency_set)

    ## Do and store PTDF calculation
    reference_bus = md.data['system']['reference_bus']

    PTDF = ptdf_utils.VirtualPTDFMatrix(branches, buses, reference_bus, base_point, ptdf_options,\
                                        contingencies=contingencies, branches_keys=branches_idx, buses_keys=buses_idx)

    model._PTDF = PTDF
    model._ptdf_options = ptdf_options

    if not ptdf_options['lazy']:
        raise RuntimeError("scopf only supports lazy constraint generation")

    ### add "blank" real power flow limits
    libbranch.declare_ineq_p_branch_thermal_bounds(
        model=model,
        index_set=branches_idx,
        branches=branches,
        p_thermal_limits=None,
        approximation_type=None,
    )

    ### add "blank" real power flow limits
    libbranch.declare_ineq_p_contingency_branch_thermal_bounds(
        model=model,
        index_set=model._contingency_set,
        pc_thermal_limits=None,
        approximation_type=None,
    )

    ### add helpers for tracking monitored branches
    lpu.add_monitored_flow_tracker(model)

    ### add initial branches to monitored set
    lpu.add_initial_monitored_branches(model, branches, branches_idx,
                                       ptdf_options, PTDF)

    ### declare the generator cost objective
    libgen.declare_expression_pgqg_operating_cost(model=model,
                                                  index_set=gen_attrs['names'],
                                                  p_costs=gen_attrs['p_cost'])

    obj_expr = sum(model.pg_operating_cost[gen_name]
                   for gen_name in model.pg_operating_cost)
    if include_feasibility_slack:
        obj_expr += penalty_expr

    model.obj = pyo.Objective(expr=obj_expr)

    return model, md
Beispiel #17
0
def create_btheta_dcopf_model(model_data):
    md = tx_utils.scale_ModelData_to_pu(model_data)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    gen_attrs = md.attributes(element_type='generator')
    bus_attrs = md.attributes(element_type='bus')
    branch_attrs = md.attributes(element_type='branch')
    load_attrs = md.attributes(element_type='load')
    shunt_attrs = md.attributes(element_type='shunt')

    inlet_branches_by_bus, outlet_branches_by_bus = \
        tx_utils.inlet_outlet_branches_by_bus(branches, buses)
    gens_by_bus = tx_utils.gens_in_service_by_bus(buses, gens)

    model = pe.ConcreteModel()

    ### declare (and fix) the loads at the buses
    bus_p_loads, _ = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads)
    model.pl.fix()

    ### declare the fixed shunts at the buses
    _, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(buses, shunts)

    ### declare the polar voltages
    va_bounds = {k: (-pi, pi) for k in bus_attrs['va']}
    libbus.declare_var_va(model,
                          bus_attrs['names'],
                          initialize=bus_attrs['va'],
                          bounds=va_bounds)

    ### fix the reference bus
    ref_bus = md.data['system']['reference_bus']
    model.va[ref_bus].fix(0.0)

    ref_angle = md.data['system']['reference_bus_angle']
    if ref_angle != 0.0:
        raise ValueError('The BTHETA DCOPF formulation currently only supports'
                         ' a reference bus angle of 0 degrees, but an angle'
                         ' of {} degrees was found.'.format(ref_angle))

    ### declare the generator real power
    pg_init = {
        k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0
        for k in gen_attrs['pg']
    }
    libgen.declare_var_pg(model,
                          gen_attrs['names'],
                          initialize=pg_init,
                          bounds=zip_items(gen_attrs['p_min'],
                                           gen_attrs['p_max']))

    ### declare the current flows in the branches
    vr_init = {
        k: bus_attrs['vm'][k] * pe.cos(bus_attrs['va'][k])
        for k in bus_attrs['vm']
    }
    vj_init = {
        k: bus_attrs['vm'][k] * pe.sin(bus_attrs['va'][k])
        for k in bus_attrs['vm']
    }
    p_max = {k: branches[k]['rating_long_term'] for k in branches.keys()}
    p_lbub = {k: (-p_max[k], p_max[k]) for k in branches.keys()}
    pf_bounds = p_lbub
    pf_init = dict()
    for branch_name, branch in branches.items():
        from_bus = branch['from_bus']
        to_bus = branch['to_bus']
        y_matrix = tx_calc.calculate_y_matrix_from_branch(branch)
        ifr_init = tx_calc.calculate_ifr(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        ifj_init = tx_calc.calculate_ifj(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        pf_init[branch_name] = tx_calc.calculate_p(ifr_init, ifj_init,
                                                   vr_init[from_bus],
                                                   vj_init[from_bus])

    libbranch.declare_var_pf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pf_init,
                             bounds=pf_bounds)

    ### declare the branch power flow approximation constraints
    libbranch.declare_eq_branch_power_dc_approx(
        model=model,
        index_set=branch_attrs['names'],
        branches=branches,
        approximation_type=ApproximationType.BTHETA)

    ### declare the p balance
    libbus.declare_eq_p_balance_dc_approx(
        model=model,
        index_set=bus_attrs['names'],
        bus_p_loads=bus_p_loads,
        gens_by_bus=gens_by_bus,
        bus_gs_fixed_shunts=bus_gs_fixed_shunts,
        inlet_branches_by_bus=inlet_branches_by_bus,
        outlet_branches_by_bus=outlet_branches_by_bus,
        approximation_type=ApproximationType.BTHETA)

    ### declare the real power flow limits
    libbranch.declare_ineq_p_branch_thermal_lbub(
        model=model,
        index_set=branch_attrs['names'],
        branches=branches,
        p_thermal_limits=p_max,
        approximation_type=ApproximationType.BTHETA)

    ### declare angle difference limits on interconnected buses
    libbranch.declare_ineq_angle_diff_branch_lbub(
        model=model,
        index_set=branch_attrs['names'],
        branches=branches,
        coordinate_type=CoordinateType.POLAR)

    ### declare the generator cost objective
    libgen.declare_expression_pgqg_operating_cost(model=model,
                                                  index_set=gen_attrs['names'],
                                                  p_costs=gen_attrs['p_cost'])

    obj_expr = sum(model.pg_operating_cost[gen_name]
                   for gen_name in model.pg_operating_cost)

    model.obj = pe.Objective(expr=obj_expr)

    return model
Beispiel #18
0
def _ptdf_dcopf_network_model(block, tm):
    m = block.model()

    buses = m._buses
    branches = m._branches
    ptdf_options = m._ptdf_options

    branches_in_service = tuple(l for l in m.TransmissionLines
                                if not value(m.LineOutOfService[l, tm]))
    ## this will serve as a key into our dict of PTDF matricies,
    ## so that we can avoid recalculating them each time step
    ## with the same network topology
    branches_out_service = tuple(l for l in m.TransmissionLines
                                 if value(m.LineOutOfService[l, tm]))

    gens_by_bus = block.gens_by_bus

    ### declare (and fix) the loads at the buses
    bus_p_loads = {b: value(m.Demand[b, tm]) for b in m.Buses}

    ## this is not the "real" gens by bus, but the
    ## index of net injections from the UC model
    libbus.declare_var_pl(block, m.Buses, initialize=bus_p_loads)
    block.pl.fix()

    ### get the fixed shunts at the buses
    bus_gs_fixed_shunts = m._bus_gs_fixed_shunts

    ### declare net withdraw expression for use in PTDF power flows
    libbus.declare_expr_p_net_withdraw_at_bus(
        model=block,
        index_set=m.Buses,
        bus_p_loads=bus_p_loads,
        gens_by_bus=gens_by_bus,
        bus_gs_fixed_shunts=bus_gs_fixed_shunts,
    )

    ### declare the p balance
    libbus.declare_eq_p_balance_ed(
        model=block,
        index_set=m.Buses,
        bus_p_loads=bus_p_loads,
        gens_by_bus=gens_by_bus,
        bus_gs_fixed_shunts=bus_gs_fixed_shunts,
    )

    ### add "blank" power flow expressions
    libbranch.declare_expr_pf(
        model=block,
        index_set=branches_in_service,
    )

    ### Get the PTDF matrix from cache, from file, or create a new one
    if branches_out_service not in m._PTDFs:
        buses_idx = tuple(buses.keys())

        reference_bus = value(m.ReferenceBus)

        PTDF = data_utils.get_ptdf_potentially_from_file(
            ptdf_options, branches_in_service, buses_idx)

        ## NOTE: For now, just use a flat-start for unit commitment
        if PTDF is None:
            PTDF = data_utils.PTDFMatrix(branches,
                                         buses,
                                         reference_bus,
                                         BasePointType.FLATSTART,
                                         branches_keys=branches_in_service,
                                         buses_keys=buses_idx)

        m._PTDFs[branches_out_service] = PTDF

    else:
        PTDF = m._PTDFs[branches_out_service]

    ### attach the current PTDF object to this block
    block._PTDF = PTDF

    if ptdf_options['lazy']:
        ### add "blank" real power flow limits
        libbranch.declare_ineq_p_branch_thermal_lbub(
            model=block,
            index_set=branches_in_service,
            branches=branches,
            p_thermal_limits=None,
            approximation_type=None,
        )

    else:  ### add all the dense constraints
        rel_ptdf_tol = m._ptdf_options['rel_ptdf_tol']
        abs_ptdf_tol = m._ptdf_options['abs_ptdf_tol']

        p_max = {
            k: branches[k]['rating_long_term']
            for k in branches_in_service
        }

        ### declare the branch power flow approximation constraints
        libbranch.declare_eq_branch_power_ptdf_approx(
            model=block,
            index_set=branches_in_service,
            PTDF=PTDF,
            abs_ptdf_tol=abs_ptdf_tol,
            rel_ptdf_tol=rel_ptdf_tol)
        ### declare the real power flow limits
        libbranch.declare_ineq_p_branch_thermal_lbub(
            model=block,
            index_set=branches_in_service,
            branches=branches,
            p_thermal_limits=p_max,
            approximation_type=ApproximationType.PTDF)
Beispiel #19
0
def create_ptdf_dcopf_model(model_data,
                            include_feasibility_slack=False,
                            base_point=BasePointType.FLATSTART,
                            ptdf_options=None):

    ptdf_options = lpu.populate_default_ptdf_options(ptdf_options)

    baseMVA = model_data.data['system']['baseMVA']
    lpu.check_and_scale_ptdf_options(ptdf_options, baseMVA)

    md = model_data.clone_in_service()
    tx_utils.scale_ModelData_to_pu(md, inplace=True)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    gen_attrs = md.attributes(element_type='generator')
    ## to keep things in order
    buses_idx = tuple(buses.keys())
    branches_idx = tuple(branches.keys())

    inlet_branches_by_bus, outlet_branches_by_bus = \
        tx_utils.inlet_outlet_branches_by_bus(branches, buses)
    gens_by_bus = tx_utils.gens_by_bus(buses, gens)

    model = pe.ConcreteModel()

    ### declare (and fix) the loads at the buses
    bus_p_loads, _ = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(model, buses_idx, initialize=bus_p_loads)
    model.pl.fix()

    ### declare the fixed shunts at the buses
    _, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(buses, shunts)

    ### declare the generator real power
    pg_init = {
        k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0
        for k in gen_attrs['pg']
    }
    libgen.declare_var_pg(model,
                          gen_attrs['names'],
                          initialize=pg_init,
                          bounds=zip_items(gen_attrs['p_min'],
                                           gen_attrs['p_max']))

    ### include the feasibility slack for the system balance
    p_rhs_kwargs = {}
    if include_feasibility_slack:
        p_rhs_kwargs, penalty_expr = _include_system_feasibility_slack(
            model, gen_attrs, bus_p_loads)

    ### declare the p balance
    libbus.declare_eq_p_balance_ed(model=model,
                                   index_set=buses_idx,
                                   bus_p_loads=bus_p_loads,
                                   gens_by_bus=gens_by_bus,
                                   bus_gs_fixed_shunts=bus_gs_fixed_shunts,
                                   **p_rhs_kwargs)

    ### declare net withdraw expression for use in PTDF power flows
    libbus.declare_expr_p_net_withdraw_at_bus(
        model=model,
        index_set=buses_idx,
        bus_p_loads=bus_p_loads,
        gens_by_bus=gens_by_bus,
        bus_gs_fixed_shunts=bus_gs_fixed_shunts,
    )

    ### add "blank" power flow expressions
    libbranch.declare_expr_pf(
        model=model,
        index_set=branches_idx,
    )

    ## Do and store PTDF calculation
    reference_bus = md.data['system']['reference_bus']

    PTDF = ptdf_utils.get_ptdf_potentially_from_file(ptdf_options,
                                                     branches_idx, buses_idx)
    if PTDF is None:
        PTDF = ptdf_utils.PTDFMatrix(branches,
                                     buses,
                                     reference_bus,
                                     base_point,
                                     ptdf_options,
                                     branches_keys=branches_idx,
                                     buses_keys=buses_idx)

    model._PTDF = PTDF
    model._ptdf_options = ptdf_options

    ptdf_utils.write_ptdf_potentially_to_file(ptdf_options, PTDF)

    if ptdf_options['lazy']:

        ### add "blank" real power flow limits
        libbranch.declare_ineq_p_branch_thermal_bounds(
            model=model,
            index_set=branches_idx,
            branches=branches,
            p_thermal_limits=None,
            approximation_type=None,
        )

        ### add helpers for tracking monitored branches
        lpu.add_monitored_flow_tracker(model)

        ### add initial branches to monitored set
        lpu.add_initial_monitored_branches(model, branches, branches_idx,
                                           ptdf_options, PTDF)

    else:
        p_max = {k: branches[k]['rating_long_term'] for k in branches.keys()}
        ## add all the constraints
        ### declare the branch power flow approximation constraints
        libbranch.declare_eq_branch_power_ptdf_approx(
            model=model,
            index_set=branches_idx,
            PTDF=PTDF,
            abs_ptdf_tol=ptdf_options['abs_ptdf_tol'],
            rel_ptdf_tol=ptdf_options['rel_ptdf_tol'],
        )

        ### add all the limits
        libbranch.declare_ineq_p_branch_thermal_lbub(
            model=model,
            index_set=branches_idx,
            branches=branches,
            p_thermal_limits=p_max,
            approximation_type=ApproximationType.PTDF,
        )

    ### declare the generator cost objective
    libgen.declare_expression_pgqg_operating_cost(model=model,
                                                  index_set=gen_attrs['names'],
                                                  p_costs=gen_attrs['p_cost'])

    obj_expr = sum(model.pg_operating_cost[gen_name]
                   for gen_name in model.pg_operating_cost)
    if include_feasibility_slack:
        obj_expr += penalty_expr

    model.obj = pe.Objective(expr=obj_expr)

    return model, md
Beispiel #20
0
def create_riv_acopf_model(model_data, include_feasibility_slack=False):
    md = model_data.clone_in_service()
    tx_utils.scale_ModelData_to_pu(md, inplace=True)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    gen_attrs = md.attributes(element_type='generator')
    bus_attrs = md.attributes(element_type='bus')
    branch_attrs = md.attributes(element_type='branch')
    load_attrs = md.attributes(element_type='load')
    shunt_attrs = md.attributes(element_type='shunt')

    inlet_branches_by_bus, outlet_branches_by_bus = \
        tx_utils.inlet_outlet_branches_by_bus(branches, buses)
    gens_by_bus = tx_utils.gens_by_bus(buses, gens)

    model = pe.ConcreteModel()

    ### declare (and fix) the loads at the buses
    bus_p_loads, bus_q_loads = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads)
    libbus.declare_var_ql(model, bus_attrs['names'], initialize=bus_q_loads)
    model.pl.fix()
    model.ql.fix()

    ### declare the fixed shunts at the buses
    bus_bs_fixed_shunts, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(
        buses, shunts)

    ### declare the rectangular voltages
    neg_v_max = map_items(op.neg, bus_attrs['v_max'])
    vr_init = {
        k: bus_attrs['vm'][k] * pe.cos(bus_attrs['va'][k])
        for k in bus_attrs['vm']
    }
    libbus.declare_var_vr(model,
                          bus_attrs['names'],
                          initialize=vr_init,
                          bounds=zip_items(neg_v_max, bus_attrs['v_max']))

    vj_init = {
        k: bus_attrs['vm'][k] * pe.sin(bus_attrs['va'][k])
        for k in bus_attrs['vm']
    }
    libbus.declare_var_vj(model,
                          bus_attrs['names'],
                          initialize=vj_init,
                          bounds=zip_items(neg_v_max, bus_attrs['v_max']))

    ### include the feasibility slack for the bus balances
    p_rhs_kwargs = {}
    q_rhs_kwargs = {}
    if include_feasibility_slack:
        p_rhs_kwargs, q_rhs_kwargs, penalty_expr = _include_feasibility_slack(
            model, bus_attrs, gen_attrs, bus_p_loads, bus_q_loads)

    ### fix the reference bus
    ref_bus = md.data['system']['reference_bus']
    ref_angle = md.data['system']['reference_bus_angle']
    if ref_angle != 0.0:
        libbus.declare_eq_ref_bus_nonzero(model, ref_angle, ref_bus)
    else:
        model.vj[ref_bus].fix(0.0)
        model.vr[ref_bus].setlb(0.0)

    ### declare the generator real and reactive power
    pg_init = {
        k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0
        for k in gen_attrs['pg']
    }
    libgen.declare_var_pg(model,
                          gen_attrs['names'],
                          initialize=pg_init,
                          bounds=zip_items(gen_attrs['p_min'],
                                           gen_attrs['p_max']))

    qg_init = {
        k: (gen_attrs['q_min'][k] + gen_attrs['q_max'][k]) / 2.0
        for k in gen_attrs['qg']
    }
    libgen.declare_var_qg(model,
                          gen_attrs['names'],
                          initialize=qg_init,
                          bounds=zip_items(gen_attrs['q_min'],
                                           gen_attrs['q_max']))

    ### declare the current flows in the branches
    branch_currents = tx_utils.dict_of_branch_currents(branches, buses)
    s_max = {k: branches[k]['rating_long_term'] for k in branches.keys()}
    if_bounds = dict()
    it_bounds = dict()
    ifr_init = dict()
    ifj_init = dict()
    itr_init = dict()
    itj_init = dict()
    for branch_name, branch in branches.items():
        from_bus = branch['from_bus']
        to_bus = branch['to_bus']
        y_matrix = tx_calc.calculate_y_matrix_from_branch(branch)
        ifr_init[branch_name] = tx_calc.calculate_ifr(vr_init[from_bus],
                                                      vj_init[from_bus],
                                                      vr_init[to_bus],
                                                      vj_init[to_bus],
                                                      y_matrix)
        ifj_init[branch_name] = tx_calc.calculate_ifj(vr_init[from_bus],
                                                      vj_init[from_bus],
                                                      vr_init[to_bus],
                                                      vj_init[to_bus],
                                                      y_matrix)
        itr_init[branch_name] = tx_calc.calculate_itr(vr_init[from_bus],
                                                      vj_init[from_bus],
                                                      vr_init[to_bus],
                                                      vj_init[to_bus],
                                                      y_matrix)
        itj_init[branch_name] = tx_calc.calculate_itj(vr_init[from_bus],
                                                      vj_init[from_bus],
                                                      vr_init[to_bus],
                                                      vj_init[to_bus],
                                                      y_matrix)
        if s_max[branch_name] is None:
            if_bounds[branch_name] = (None, None)
            it_bounds[branch_name] = (None, None)
        else:
            if_max = s_max[branch_name] / buses[branches[branch_name]
                                                ['from_bus']]['v_min']
            it_max = s_max[branch_name] / buses[branches[branch_name]
                                                ['to_bus']]['v_min']
            if_bounds[branch_name] = (-if_max, if_max)
            it_bounds[branch_name] = (-it_max, it_max)

    libbranch.declare_var_ifr(model=model,
                              index_set=branch_attrs['names'],
                              initialize=ifr_init,
                              bounds=if_bounds)
    libbranch.declare_var_ifj(model=model,
                              index_set=branch_attrs['names'],
                              initialize=ifj_init,
                              bounds=if_bounds)
    libbranch.declare_var_itr(model=model,
                              index_set=branch_attrs['names'],
                              initialize=itr_init,
                              bounds=it_bounds)
    libbranch.declare_var_itj(model=model,
                              index_set=branch_attrs['names'],
                              initialize=itj_init,
                              bounds=it_bounds)

    ir_init = dict()
    ij_init = dict()
    for bus_name, bus in buses.items():
        ir_expr = sum([
            ifr_init[branch_name]
            for branch_name in outlet_branches_by_bus[bus_name]
        ])
        ir_expr += sum([
            itr_init[branch_name]
            for branch_name in inlet_branches_by_bus[bus_name]
        ])
        ij_expr = sum([
            ifj_init[branch_name]
            for branch_name in outlet_branches_by_bus[bus_name]
        ])
        ij_expr += sum([
            itj_init[branch_name]
            for branch_name in inlet_branches_by_bus[bus_name]
        ])

        if bus_gs_fixed_shunts[bus_name] != 0.0:
            ir_expr += bus_gs_fixed_shunts[bus_name] * vr_init[bus_name]
            ij_expr += bus_gs_fixed_shunts[bus_name] * vj_init[bus_name]
        if bus_bs_fixed_shunts[bus_name] != 0.0:
            ir_expr += bus_bs_fixed_shunts[bus_name] * vj_init[bus_name]
            ij_expr += bus_bs_fixed_shunts[bus_name] * vr_init[bus_name]

        ir_init[bus_name] = ir_expr
        ij_init[bus_name] = ij_expr

    # TODO: Implement better bounds (?) for these aggregated variables -- note, these are unbounded in old Egret
    libbus.declare_var_ir_aggregation_at_bus(model=model,
                                             index_set=bus_attrs['names'],
                                             initialize=ir_init,
                                             bounds=(None, None))
    libbus.declare_var_ij_aggregation_at_bus(model=model,
                                             index_set=bus_attrs['names'],
                                             initialize=ij_init,
                                             bounds=(None, None))

    ### declare the branch current flow constraints
    libbranch.declare_eq_branch_current(model=model,
                                        index_set=branch_attrs['names'],
                                        branches=branches)

    ### declare the ir/ij_aggregation constraints
    libbus.declare_eq_i_aggregation_at_bus(
        model=model,
        index_set=bus_attrs['names'],
        bus_bs_fixed_shunts=bus_bs_fixed_shunts,
        bus_gs_fixed_shunts=bus_gs_fixed_shunts,
        inlet_branches_by_bus=inlet_branches_by_bus,
        outlet_branches_by_bus=outlet_branches_by_bus)

    ### declare the pq balances
    libbus.declare_eq_p_balance_with_i_aggregation(
        model=model,
        index_set=bus_attrs['names'],
        bus_p_loads=bus_p_loads,
        gens_by_bus=gens_by_bus,
        **p_rhs_kwargs)

    libbus.declare_eq_q_balance_with_i_aggregation(
        model=model,
        index_set=bus_attrs['names'],
        bus_q_loads=bus_q_loads,
        gens_by_bus=gens_by_bus,
        **q_rhs_kwargs)

    ### declare the thermal limits
    libbranch.declare_ineq_s_branch_thermal_limit(
        model=model,
        index_set=branch_attrs['names'],
        branches=branches,
        s_thermal_limits=s_max,
        flow_type=FlowType.CURRENT)

    ### declare the voltage min and max inequalities
    libbus.declare_ineq_vm_bus_lbub(model=model,
                                    index_set=bus_attrs['names'],
                                    buses=buses,
                                    coordinate_type=CoordinateType.RECTANGULAR)

    ### declare angle difference limits on interconnected buses
    libbranch.declare_ineq_angle_diff_branch_lbub(
        model=model,
        index_set=branch_attrs['names'],
        branches=branches,
        coordinate_type=CoordinateType.RECTANGULAR)

    ### declare the generator cost objective
    libgen.declare_expression_pgqg_operating_cost(model=model,
                                                  index_set=gen_attrs['names'],
                                                  p_costs=gen_attrs['p_cost'],
                                                  q_costs=gen_attrs.get(
                                                      'q_cost', None))

    obj_expr = sum(model.pg_operating_cost[gen_name]
                   for gen_name in model.pg_operating_cost)
    if include_feasibility_slack:
        obj_expr += penalty_expr
    if hasattr(model, 'qg_operating_cost'):
        obj_expr += sum(model.qg_operating_cost[gen_name]
                        for gen_name in model.qg_operating_cost)

    model.obj = pe.Objective(expr=obj_expr)

    return model, md
def create_copperplate_dispatch_approx_model(model_data,
                                             include_feasibility_slack=False):
    md = model_data.clone_in_service()
    tx_utils.scale_ModelData_to_pu(md, inplace=True)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    gen_attrs = md.attributes(element_type='generator')
    bus_attrs = md.attributes(element_type='bus')

    inlet_branches_by_bus, outlet_branches_by_bus = \
        tx_utils.inlet_outlet_branches_by_bus(branches, buses)
    gens_by_bus = tx_utils.gens_by_bus(buses, gens)

    model = pe.ConcreteModel()

    ### declare (and fix) the loads at the buses
    bus_p_loads, _ = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads)
    model.pl.fix()

    ### declare the fixed shunts at the buses
    _, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(buses, shunts)

    ### declare the generator real power
    pg_init = {
        k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0
        for k in gen_attrs['pg']
    }
    libgen.declare_var_pg(model,
                          gen_attrs['names'],
                          initialize=pg_init,
                          bounds=zip_items(gen_attrs['p_min'],
                                           gen_attrs['p_max']))

    ### include the feasibility slack for the system balance
    p_rhs_kwargs = {}
    if include_feasibility_slack:
        p_marginal_slack_penalty = _validate_and_extract_slack_penalty(
            model_data)
        p_rhs_kwargs, penalty_expr = _include_system_feasibility_slack(
            model, bus_p_loads, gen_attrs, p_marginal_slack_penalty)

    ### declare the p balance
    libbus.declare_eq_p_balance_ed(model=model,
                                   index_set=bus_attrs['names'],
                                   bus_p_loads=bus_p_loads,
                                   gens_by_bus=gens_by_bus,
                                   bus_gs_fixed_shunts=bus_gs_fixed_shunts,
                                   **p_rhs_kwargs)

    ### declare the generator cost objective
    libgen.declare_expression_pgqg_operating_cost(model=model,
                                                  index_set=gen_attrs['names'],
                                                  p_costs=gen_attrs['p_cost'])

    obj_expr = sum(model.pg_operating_cost[gen_name]
                   for gen_name in model.pg_operating_cost)
    if include_feasibility_slack:
        obj_expr += penalty_expr

    model.obj = pe.Objective(expr=obj_expr)

    return model, md
Beispiel #22
0
def _create_base_relaxation(model_data):
    md = model_data.clone_in_service()
    tx_utils.scale_ModelData_to_pu(md, inplace=True)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    gen_attrs = md.attributes(element_type='generator')
    bus_attrs = md.attributes(element_type='bus')
    branch_attrs = md.attributes(element_type='branch')

    inlet_branches_by_bus, outlet_branches_by_bus = \
        tx_utils.inlet_outlet_branches_by_bus(branches, buses)
    gens_by_bus = tx_utils.gens_by_bus(buses, gens)

    bus_pairs = zip_items(branch_attrs['from_bus'], branch_attrs['to_bus'])
    unique_bus_pairs = list(
        OrderedDict((val, None) for idx, val in bus_pairs.items()))

    model = pe.ConcreteModel()

    ### declare (and fix) the loads at the buses
    bus_p_loads, bus_q_loads = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads)
    libbus.declare_var_ql(model, bus_attrs['names'], initialize=bus_q_loads)
    model.pl.fix()
    model.ql.fix()

    ### declare the fixed shunts at the buses
    bus_bs_fixed_shunts, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(
        buses, shunts)

    libbus.declare_var_vmsq(
        model=model,
        index_set=bus_attrs['names'],
        initialize={k: v**2
                    for k, v in bus_attrs['vm'].items()},
        bounds=zip_items({k: v**2
                          for k, v in bus_attrs['v_min'].items()},
                         {k: v**2
                          for k, v in bus_attrs['v_max'].items()}))
    libbranch.declare_var_c(model=model, index_set=unique_bus_pairs)
    libbranch.declare_var_s(model=model, index_set=unique_bus_pairs)

    ### declare the generator real and reactive power
    pg_init = {
        k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0
        for k in gen_attrs['pg']
    }
    libgen.declare_var_pg(model,
                          gen_attrs['names'],
                          initialize=pg_init,
                          bounds=zip_items(gen_attrs['p_min'],
                                           gen_attrs['p_max']))

    qg_init = {
        k: (gen_attrs['q_min'][k] + gen_attrs['q_max'][k]) / 2.0
        for k in gen_attrs['qg']
    }
    libgen.declare_var_qg(model,
                          gen_attrs['names'],
                          initialize=qg_init,
                          bounds=zip_items(gen_attrs['q_min'],
                                           gen_attrs['q_max']))

    ### declare the current flows in the branches
    vr_init = {
        k: bus_attrs['vm'][k] * pe.cos(bus_attrs['va'][k])
        for k in bus_attrs['vm']
    }
    vj_init = {
        k: bus_attrs['vm'][k] * pe.sin(bus_attrs['va'][k])
        for k in bus_attrs['vm']
    }
    s_max = {k: branches[k]['rating_long_term'] for k in branches.keys()}
    s_lbub = dict()
    for k in branches.keys():
        if s_max[k] is None:
            s_lbub[k] = (None, None)
        else:
            s_lbub[k] = (-s_max[k], s_max[k])
    pf_bounds = s_lbub
    pt_bounds = s_lbub
    qf_bounds = s_lbub
    qt_bounds = s_lbub
    pf_init = dict()
    pt_init = dict()
    qf_init = dict()
    qt_init = dict()
    for branch_name, branch in branches.items():
        from_bus = branch['from_bus']
        to_bus = branch['to_bus']
        y_matrix = tx_calc.calculate_y_matrix_from_branch(branch)
        ifr_init = tx_calc.calculate_ifr(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        ifj_init = tx_calc.calculate_ifj(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        itr_init = tx_calc.calculate_itr(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        itj_init = tx_calc.calculate_itj(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        pf_init[branch_name] = tx_calc.calculate_p(ifr_init, ifj_init,
                                                   vr_init[from_bus],
                                                   vj_init[from_bus])
        pt_init[branch_name] = tx_calc.calculate_p(itr_init, itj_init,
                                                   vr_init[to_bus],
                                                   vj_init[to_bus])
        qf_init[branch_name] = tx_calc.calculate_q(ifr_init, ifj_init,
                                                   vr_init[from_bus],
                                                   vj_init[from_bus])
        qt_init[branch_name] = tx_calc.calculate_q(itr_init, itj_init,
                                                   vr_init[to_bus],
                                                   vj_init[to_bus])

    libbranch.declare_var_pf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pf_init,
                             bounds=pf_bounds)
    libbranch.declare_var_pt(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pt_init,
                             bounds=pt_bounds)
    libbranch.declare_var_qf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=qf_init,
                             bounds=qf_bounds)
    libbranch.declare_var_qt(model=model,
                             index_set=branch_attrs['names'],
                             initialize=qt_init,
                             bounds=qt_bounds)

    ### declare the branch power flow constraints
    libbranch.declare_eq_branch_power(model=model,
                                      index_set=branch_attrs['names'],
                                      branches=branches)

    ### declare the pq balances
    libbus.declare_eq_p_balance(model=model,
                                index_set=bus_attrs['names'],
                                bus_p_loads=bus_p_loads,
                                gens_by_bus=gens_by_bus,
                                bus_gs_fixed_shunts=bus_gs_fixed_shunts,
                                inlet_branches_by_bus=inlet_branches_by_bus,
                                outlet_branches_by_bus=outlet_branches_by_bus)

    libbus.declare_eq_q_balance(model=model,
                                index_set=bus_attrs['names'],
                                bus_q_loads=bus_q_loads,
                                gens_by_bus=gens_by_bus,
                                bus_bs_fixed_shunts=bus_bs_fixed_shunts,
                                inlet_branches_by_bus=inlet_branches_by_bus,
                                outlet_branches_by_bus=outlet_branches_by_bus)

    ### declare the thermal limits
    libbranch.declare_ineq_s_branch_thermal_limit(
        model=model,
        index_set=branch_attrs['names'],
        branches=branches,
        s_thermal_limits=s_max,
        flow_type=FlowType.POWER)

    ### declare the generator cost objective
    libgen.declare_expression_pgqg_operating_cost(model=model,
                                                  index_set=gen_attrs['names'],
                                                  p_costs=gen_attrs['p_cost'],
                                                  q_costs=gen_attrs.get(
                                                      'q_cost', None))

    obj_expr = sum(model.pg_operating_cost[gen_name]
                   for gen_name in model.pg_operating_cost)
    if hasattr(model, 'qg_operating_cost'):
        obj_expr += sum(model.qg_operating_cost[gen_name]
                        for gen_name in model.qg_operating_cost)

    model.obj = pe.Objective(expr=obj_expr)

    return model, md
Beispiel #23
0
def create_cold_start_lpac_model(model_data,
                                 cosine_segment_count=20,
                                 lower_bound=-pi / 3,
                                 upper_bound=pi / 3,
                                 include_feasibility_slack=False,
                                 mode="uniform"):
    """
	The cold start LPAC model assumes that no target voltages are available and that all voltages are initially approximated as 1 pu. 
	"""
    ###Grid data
    md = model_data.clone_in_service()
    tx_utils.scale_ModelData_to_pu(md, inplace=True)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    gen_attrs = md.attributes(element_type='generator')
    bus_attrs = md.attributes(element_type='bus')
    branch_attrs = md.attributes(element_type='branch')

    inlet_branches_by_bus, outlet_branches_by_bus = \
           tx_utils.inlet_outlet_branches_by_bus(branches, buses)

    gens_by_bus = tx_utils.gens_by_bus(buses, gens)

    model = pe.ConcreteModel()

    ### declare the polar voltages
    libbus.declare_var_va(model,
                          bus_attrs['names'],
                          initialize=bus_attrs['va'])

    libbus.declare_var_vmsq(
        model=model,
        index_set=bus_attrs['names'],
        initialize={k: v**2
                    for k, v in bus_attrs['vm'].items()},
        bounds=zip_items({k: v**2
                          for k, v in bus_attrs['v_min'].items()},
                         {k: v**2
                          for k, v in bus_attrs['v_max'].items()}))

    ### declare the voltage change variables
    decl.declare_var('phi', model, bus_attrs['names'])

    ### declare the cosine approximation variables
    cos_hat_bounds = {k: (0, 1) for k in branch_attrs['names']}
    decl.declare_var('cos_hat',
                     model,
                     branch_attrs['names'],
                     bounds=cos_hat_bounds)

    ### fix the reference bus
    ref_bus = md.data['system']['reference_bus']
    #ref_angle = md.data['system']['reference_bus_angle']
    model.va[ref_bus].fix(radians(0.0))

    ### declare (and fix) the loads at the buses
    bus_p_loads, bus_q_loads = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads)
    libbus.declare_var_ql(model, bus_attrs['names'], initialize=bus_q_loads)
    model.pl.fix()
    model.ql.fix()

    ### declare the fixed shunts at the buses
    bus_bs_fixed_shunts, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(
        buses, shunts)

    ### include the feasibility slack for the bus balances
    p_rhs_kwargs = {}
    q_rhs_kwargs = {}
    if include_feasibility_slack:
        p_rhs_kwargs, q_rhs_kwargs, penalty_expr = _include_feasibility_slack(
            model, bus_attrs, gen_attrs, bus_p_loads, bus_q_loads)

### declare the generator real and reactive power
    pg_init = {
        k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0
        for k in gen_attrs['pg']
    }
    libgen.declare_var_pg(model,
                          gen_attrs['names'],
                          initialize=pg_init,
                          bounds=zip_items(gen_attrs['p_min'],
                                           gen_attrs['p_max']))

    qg_init = {
        k: (gen_attrs['q_min'][k] + gen_attrs['q_max'][k]) / 2.0
        for k in gen_attrs['qg']
    }
    libgen.declare_var_qg(model,
                          gen_attrs['names'],
                          initialize=qg_init,
                          bounds=zip_items(gen_attrs['q_min'],
                                           gen_attrs['q_max']))

    ### declare the current flows in the branches
    vr_init = {
        k: bus_attrs['vm'][k] * pe.cos(bus_attrs['va'][k])
        for k in bus_attrs['vm']
    }
    vj_init = {
        k: bus_attrs['vm'][k] * pe.sin(bus_attrs['va'][k])
        for k in bus_attrs['vm']
    }
    s_max = {k: branches[k]['rating_long_term'] for k in branches.keys()}
    s_lbub = dict()
    for k in branches.keys():
        if s_max[k] is None:
            s_lbub[k] = (None, None)
        else:
            s_lbub[k] = (-s_max[k], s_max[k])
    pf_bounds = s_lbub
    pt_bounds = s_lbub
    qf_bounds = s_lbub
    qt_bounds = s_lbub
    pf_init = dict()
    pt_init = dict()
    qf_init = dict()
    qt_init = dict()
    for branch_name, branch in branches.items():
        from_bus = branch['from_bus']
        to_bus = branch['to_bus']
        y_matrix = tx_calc.calculate_y_matrix_from_branch(branch)
        ifr_init = tx_calc.calculate_ifr(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        ifj_init = tx_calc.calculate_ifj(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        itr_init = tx_calc.calculate_itr(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        itj_init = tx_calc.calculate_itj(vr_init[from_bus], vj_init[from_bus],
                                         vr_init[to_bus], vj_init[to_bus],
                                         y_matrix)
        pf_init[branch_name] = tx_calc.calculate_p(ifr_init, ifj_init,
                                                   vr_init[from_bus],
                                                   vj_init[from_bus])
        pt_init[branch_name] = tx_calc.calculate_p(itr_init, itj_init,
                                                   vr_init[to_bus],
                                                   vj_init[to_bus])
        qf_init[branch_name] = tx_calc.calculate_q(ifr_init, ifj_init,
                                                   vr_init[from_bus],
                                                   vj_init[from_bus])
        qt_init[branch_name] = tx_calc.calculate_q(itr_init, itj_init,
                                                   vr_init[to_bus],
                                                   vj_init[to_bus])

    libbranch.declare_var_pf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pf_init,
                             bounds=pf_bounds)
    libbranch.declare_var_pt(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pt_init,
                             bounds=pt_bounds)
    libbranch.declare_var_qf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=qf_init,
                             bounds=qf_bounds)
    libbranch.declare_var_qt(model=model,
                             index_set=branch_attrs['names'],
                             initialize=qt_init,
                             bounds=qt_bounds)

    ################################
    #Constraints
    ################################

    ### Balance equations at a bus (based on Kirchhoff Current Law)

    #Should be able to just use DC OPF approximation of B-theta type?

    ### declare the p balance
    libbus.declare_eq_p_balance(model=model,
                                index_set=bus_attrs['names'],
                                bus_p_loads=bus_p_loads,
                                gens_by_bus=gens_by_bus,
                                bus_gs_fixed_shunts=bus_gs_fixed_shunts,
                                inlet_branches_by_bus=inlet_branches_by_bus,
                                outlet_branches_by_bus=outlet_branches_by_bus,
                                approximation_type=ApproximationType.BTHETA,
                                **p_rhs_kwargs)

    #Need one also for q balance

    libbus.declare_eq_q_balance(model=model,
                                index_set=bus_attrs['names'],
                                bus_q_loads=bus_q_loads,
                                gens_by_bus=gens_by_bus,
                                bus_bs_fixed_shunts=bus_bs_fixed_shunts,
                                inlet_branches_by_bus=inlet_branches_by_bus,
                                outlet_branches_by_bus=outlet_branches_by_bus,
                                **q_rhs_kwargs)

    ### Constraints for power in a branch

    branch_con_set = decl.declare_set('_con_eq_p_q_lpac_branch_power', model,
                                      branch_attrs['names'])

    model.eq_pf_branch_t = pe.Constraint(branch_con_set)
    model.eq_pt_branch_t = pe.Constraint(branch_con_set)
    model.eq_qf_branch_t = pe.Constraint(branch_con_set)
    model.eq_qt_branch_t = pe.Constraint(branch_con_set)

    for branch_name in branch_con_set:
        branch = branches[branch_name]

        from_bus = branch['from_bus']
        to_bus = branch['to_bus']

        g = tx_calc.calculate_conductance(branch)
        b = tx_calc.calculate_susceptance(branch)

        model.eq_pf_branch_t[branch_name] = \
               model.pf[branch_name] == \
               g - g * model.cos_hat[branch_name] - b * (model.va[from_bus] - model.va[to_bus])

        model.eq_pt_branch_t[branch_name] = \
               model.pt[branch_name] == \
               g - g * model.cos_hat[branch_name] - b * (model.va[to_bus] - model.va[from_bus])

        model.eq_qf_branch_t[branch_name] = \
               model.qf[branch_name] == \
               -b - g*(model.va[from_bus] - model.va[to_bus]) + b*model.cos_hat[branch_name] - b*(model.phi[from_bus] - model.phi[to_bus])

        model.eq_qt_branch_t[branch_name] = \
               model.qt[branch_name] == \
               -b - g*(model.va[to_bus] - model.va[from_bus]) +b*model.cos_hat[branch_name] - b*(model.phi[to_bus] - model.phi[from_bus])

### Piecewise linear cosine constraints

    model.N = pe.Set(initialize=list(range(cosine_segment_count + 1)))

    declare_pwl_cosine_bounds(model=model,
                              index_set=branch_attrs['names'],
                              branches=branches,
                              lower_bound=lower_bound,
                              upper_bound=upper_bound,
                              cosine_segment_count=cosine_segment_count,
                              mode=mode)

    ### Objective is to maximize cosine hat variables

    # obj_expr = sum(model.cos_hat[branch_name] for branch_name in branch_attrs['names'])

    # if include_feasibility_slack:
    # 	obj_expr += penalty_expr

    # model.obj = pe.Objective(expr=obj_expr)

    ###Objective to match with acopf.py

    ### declare the generator cost objective
    libgen.declare_expression_pgqg_operating_cost(model=model,
                                                  index_set=gen_attrs['names'],
                                                  p_costs=gen_attrs['p_cost'],
                                                  q_costs=gen_attrs.get(
                                                      'q_cost', None))

    obj_expr = sum(model.pg_operating_cost[gen_name]
                   for gen_name in model.pg_operating_cost)
    if include_feasibility_slack:
        obj_expr += penalty_expr
    if hasattr(model, 'qg_operating_cost'):
        obj_expr += sum(model.qg_operating_cost[gen_name]
                        for gen_name in model.qg_operating_cost)

    model.obj = pe.Objective(expr=obj_expr)

    return model, md
Beispiel #24
0
def create_btheta_losses_dcopf_model(model_data, relaxation_type=RelaxationType.SOC, include_angle_diff_limits=False, include_feasibility_slack=False):
    md = model_data.clone_in_service()
    tx_utils.scale_ModelData_to_pu(md, inplace = True)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    gen_attrs = md.attributes(element_type='generator')
    bus_attrs = md.attributes(element_type='bus')
    branch_attrs = md.attributes(element_type='branch')
    load_attrs = md.attributes(element_type='load')
    shunt_attrs = md.attributes(element_type='shunt')

    inlet_branches_by_bus, outlet_branches_by_bus = \
        tx_utils.inlet_outlet_branches_by_bus(branches, buses)
    gens_by_bus = tx_utils.gens_by_bus(buses, gens)

    model = pe.ConcreteModel()

    ### declare (and fix) the loads at the buses
    bus_p_loads, _ = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads)
    model.pl.fix()

    ### declare the fixed shunts at the buses
    _, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(buses, shunts)

    ### declare the polar voltages
    va_bounds = {k: (-pi, pi) for k in bus_attrs['va']}
    libbus.declare_var_va(model, bus_attrs['names'], initialize=bus_attrs['va'],
                          bounds=va_bounds
                          )

    dva_initialize = {k: 0.0 for k in branch_attrs['names']}
    libbranch.declare_var_dva(model, branch_attrs['names'],
                              initialize=dva_initialize
                              )

    ### include the feasibility slack for the bus balances
    p_rhs_kwargs = {}
    penalty_expr = None
    if include_feasibility_slack:
        p_rhs_kwargs, penalty_expr = _include_feasibility_slack(model, bus_attrs, gen_attrs, bus_p_loads)

    ### fix the reference bus
    ref_bus = md.data['system']['reference_bus']
    ref_angle = md.data['system']['reference_bus_angle']
    model.va[ref_bus].fix(radians(ref_angle))

    ### declare the generator real power
    pg_init = {k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0 for k in gen_attrs['pg']}
    libgen.declare_var_pg(model, gen_attrs['names'], initialize=pg_init,
                          bounds=zip_items(gen_attrs['p_min'], gen_attrs['p_max'])
                          )

    ### declare the current flows in the branches
    vr_init = {k: bus_attrs['vm'][k] * pe.cos(bus_attrs['va'][k]) for k in bus_attrs['vm']}
    vj_init = {k: bus_attrs['vm'][k] * pe.sin(bus_attrs['va'][k]) for k in bus_attrs['vm']}
    p_max = {k: branches[k]['rating_long_term'] for k in branches.keys()}
    pf_bounds = {k: (-p_max[k],p_max[k]) for k in branches.keys()}
    pf_init = dict()
    for branch_name, branch in branches.items():
        from_bus = branch['from_bus']
        to_bus = branch['to_bus']
        y_matrix = tx_calc.calculate_y_matrix_from_branch(branch)
        ifr_init = tx_calc.calculate_ifr(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        ifj_init = tx_calc.calculate_ifj(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        pf_init[branch_name] = tx_calc.calculate_p(ifr_init, ifj_init, vr_init[from_bus], vj_init[from_bus])
    pfl_bounds = {k: (0,p_max[k]**2) for k in branches.keys()}
    pfl_init = {k: 0 for k in branches.keys()}

    libbranch.declare_var_pf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pf_init,
                             bounds=pf_bounds
                             )

    libbranch.declare_var_pfl(model=model,
                              index_set=branch_attrs['names'],
                              initialize=pfl_init,
                              bounds=pfl_bounds
                             )

    ### declare the angle difference constraint
    libbranch.declare_eq_branch_dva(model=model,
                                    index_set=branch_attrs['names'],
                                    branches=branches
                                    )

    ### declare the branch power flow approximation constraints
    libbranch.declare_eq_branch_power_btheta_approx(model=model,
                                                    index_set=branch_attrs['names'],
                                                    branches=branches,
                                                    approximation_type=ApproximationType.BTHETA_LOSSES
                                                    )

    ### declare the branch power loss approximation constraints
    libbranch.declare_eq_branch_loss_btheta_approx(model=model,
                                                    index_set=branch_attrs['names'],
                                                    branches=branches,
                                                    relaxation_type=relaxation_type
                                                    )

    ### declare the p balance
    libbus.declare_eq_p_balance_dc_approx(model=model,
                                          index_set=bus_attrs['names'],
                                          bus_p_loads=bus_p_loads,
                                          gens_by_bus=gens_by_bus,
                                          bus_gs_fixed_shunts=bus_gs_fixed_shunts,
                                          inlet_branches_by_bus=inlet_branches_by_bus,
                                          outlet_branches_by_bus=outlet_branches_by_bus,
                                          approximation_type=ApproximationType.BTHETA_LOSSES,
                                          **p_rhs_kwargs
                                          )

    ### declare the real power flow limits
    libbranch.declare_ineq_p_branch_thermal_lbub(model=model,
                                                 index_set=branch_attrs['names'],
                                                 branches=branches,
                                                 p_thermal_limits=p_max,
                                                 approximation_type=ApproximationType.BTHETA
                                                 )

    ### declare angle difference limits on interconnected buses
    if include_angle_diff_limits:
        libbranch.declare_ineq_angle_diff_branch_lbub(model=model,
                                                      index_set=branch_attrs['names'],
                                                      branches=branches,
                                                      coordinate_type=CoordinateType.POLAR
                                                      )

    ### declare the generator cost objective
    libgen.declare_expression_pgqg_operating_cost(model=model,
                                                  index_set=gen_attrs['names'],
                                                  p_costs=gen_attrs['p_cost']
                                                  )

    obj_expr = sum(model.pg_operating_cost[gen_name] for gen_name in model.pg_operating_cost)
    if include_feasibility_slack:
        obj_expr += penalty_expr

    model.obj = pe.Objective(expr=obj_expr)

    return model, md
Beispiel #25
0
def _create_base_ac_with_pwl_approx_model(model_data, branch_dict, Q, include_feasibility_slack=False):
    md = model_data.clone_in_service()
    tx_utils.scale_ModelData_to_pu(md, inplace = True)

    gens = dict(md.elements(element_type='generator'))
    buses = dict(md.elements(element_type='bus'))
    branches = dict(md.elements(element_type='branch'))
    loads = dict(md.elements(element_type='load'))
    shunts = dict(md.elements(element_type='shunt'))

    gen_attrs = md.attributes(element_type='generator')
    bus_attrs = md.attributes(element_type='bus')
    branch_attrs = md.attributes(element_type='branch')

    inlet_branches_by_bus, outlet_branches_by_bus = \
        tx_utils.inlet_outlet_branches_by_bus(branches, buses)
    gens_by_bus = tx_utils.gens_by_bus(buses, gens)

    bus_pairs = zip_items(branch_attrs['from_bus'], branch_attrs['to_bus'])
    unique_bus_pairs = list(OrderedDict((val, None) for idx, val in bus_pairs.items()))

    model = pe.ConcreteModel()

    ### declare (and fix) the loads at the buses
    bus_p_loads, bus_q_loads = tx_utils.dict_of_bus_loads(buses, loads)

    libbus.declare_var_pl(model, bus_attrs['names'], initialize=bus_p_loads)
    libbus.declare_var_ql(model, bus_attrs['names'], initialize=bus_q_loads)
    model.pl.fix()
    model.ql.fix()

    ### declare the fixed shunts at the buses
    bus_bs_fixed_shunts, bus_gs_fixed_shunts = tx_utils.dict_of_bus_fixed_shunts(buses, shunts)

    libbus.declare_var_vm(model=model, index_set=bus_attrs['names'], initialize=bus_attrs['vm'], bounds=zip_items(bus_attrs['v_min'], bus_attrs['v_max']))

    libbus.declare_var_vmsq(model=model,
                            index_set=bus_attrs['names'],
                            initialize={k: v**2 for k, v in bus_attrs['vm'].items()},
                            bounds=zip_items({k: v**2 for k, v in bus_attrs['v_min'].items()},
                                             {k: v**2 for k, v in bus_attrs['v_max'].items()}))
    # libbranch.declare_var_c(model=model, index_set=unique_bus_pairs)
    # libbranch.declare_var_s(model=model, index_set=unique_bus_pairs)

    ### declare the polar voltages
    va_bounds = {k: (-math.pi, math.pi) for k in bus_attrs['va']}
    libbus.declare_var_va(model, bus_attrs['names'], initialize=bus_attrs['va'],
                          bounds=va_bounds
                          )

    ###declare the phase angle differences in each branch
    libbranch.declare_var_dva(model, index_set=unique_bus_pairs)

    libbranch.declare_eq_delta_va(model, index_set=unique_bus_pairs)

    ### include the feasibility slack for the bus balances
    p_rhs_kwargs = {}
    q_rhs_kwargs = {}
    if include_feasibility_slack:
        p_rhs_kwargs, q_rhs_kwargs, penalty_expr = _include_feasibility_slack(model, bus_attrs, gen_attrs, bus_p_loads, bus_q_loads)

    ### declare the generator real and reactive power
    pg_init = {k: (gen_attrs['p_min'][k] + gen_attrs['p_max'][k]) / 2.0 for k in gen_attrs['pg']}
    libgen.declare_var_pg(model, gen_attrs['names'], initialize=pg_init,
                          bounds=zip_items(gen_attrs['p_min'], gen_attrs['p_max'])
                          )

    qg_init = {k: (gen_attrs['q_min'][k] + gen_attrs['q_max'][k]) / 2.0 for k in gen_attrs['qg']}
    libgen.declare_var_qg(model, gen_attrs['names'], initialize=qg_init,
                          bounds=zip_items(gen_attrs['q_min'], gen_attrs['q_max'])
                          )

    ### declare the current flows in the branches
    vr_init = {k: bus_attrs['vm'][k] * pe.cos(bus_attrs['va'][k]) for k in bus_attrs['vm']}
    vj_init = {k: bus_attrs['vm'][k] * pe.sin(bus_attrs['va'][k]) for k in bus_attrs['vm']}
    s_max = {k: branches[k]['rating_long_term'] for k in branches.keys()}
    s_lbub = dict()
    for k in branches.keys():
        if s_max[k] is None:
            s_lbub[k] = (None, None)
        else:
            s_lbub[k] = (-s_max[k],s_max[k])
    pf_bounds = s_lbub
    pt_bounds = s_lbub
    qf_bounds = s_lbub
    qt_bounds = s_lbub
    pf_init = dict()
    pt_init = dict()
    qf_init = dict()
    qt_init = dict()
    for branch_name, branch in branches.items():
        from_bus = branch['from_bus']
        to_bus = branch['to_bus']
        y_matrix = tx_calc.calculate_y_matrix_from_branch(branch)
        ifr_init = tx_calc.calculate_ifr(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        ifj_init = tx_calc.calculate_ifj(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        itr_init = tx_calc.calculate_itr(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        itj_init = tx_calc.calculate_itj(vr_init[from_bus], vj_init[from_bus], vr_init[to_bus],
                                         vj_init[to_bus], y_matrix)
        pf_init[branch_name] = tx_calc.calculate_p(ifr_init, ifj_init, vr_init[from_bus], vj_init[from_bus])
        pt_init[branch_name] = tx_calc.calculate_p(itr_init, itj_init, vr_init[to_bus], vj_init[to_bus])
        qf_init[branch_name] = tx_calc.calculate_q(ifr_init, ifj_init, vr_init[from_bus], vj_init[from_bus])
        qt_init[branch_name] = tx_calc.calculate_q(itr_init, itj_init, vr_init[to_bus], vj_init[to_bus])

    libbranch.declare_var_pf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pf_init,
                             bounds=pf_bounds
                             )
    libbranch.declare_var_pt(model=model,
                             index_set=branch_attrs['names'],
                             initialize=pt_init,
                             bounds=pt_bounds
                             )
    libbranch.declare_var_qf(model=model,
                             index_set=branch_attrs['names'],
                             initialize=qf_init,
                             bounds=qf_bounds
                             )
    libbranch.declare_var_qt(model=model,
                             index_set=branch_attrs['names'],
                             initialize=qt_init,
                             bounds=qt_bounds
                             )

    ### declare the branch power flow constraints



    ### declare a binary on/off variable for deenergizing a given branch

    decl.declare_var('u', model=model, index_set=branch_attrs['names'], within=pe.Binary)

    model.u.fix(1)

    branch_name_set = decl.declare_set('branch_name', model=model, index_set=branch_attrs['names'])

    model.box_index_set = pe.RangeSet(Q)

    model.power_type_set = pe.Set(initialize=[0,1])
    #Note: 0 is for power_type == "Active"; 1 is for power_type=="Reactive"

    #For active power energization/deenergization
    model.u_branch = pe.Var(branch_name_set, model.box_index_set, model.power_type_set, within=pe.Binary)

    #For selecting the appropriate interval of the PWL approximation
    model.dva_branch = pe.Var(branch_name_set, model.box_index_set, model.power_type_set)

    #(5) - Constraints for the on/off variable u

    def u_sum_rule(model, branch_name, j):
    	return model.u[branch_name] == sum(model.u_branch[branch_name, i, j] for i in model.box_index_set)

    model.u_sum_Constr = pe.Constraint(branch_name_set, model.power_type_set, rule=u_sum_rule)


    #(6) - Constraints that sum of dva variables should be equal to total dva

    #Upper bound constraints

    def delta_branch_ub_rule(model, branch_name, j):
    	branch = branches[branch_name]

    	from_bus = branch['from_bus']
    	to_bus = branch['to_bus']

    	return -model.dva[(from_bus, to_bus)] + sum(model.dva_branch[branch_name, i, j] for i in model.box_index_set) <= math.pi*(1-model.u[branch_name])

    model.delta_branch_ub_Constr = pe.Constraint(branch_name_set, model.power_type_set, rule=delta_branch_ub_rule)

    #Lower bound constraints

    def delta_branch_lb_rule(model, branch_name, j):
    	branch = branches[branch_name]

    	from_bus = branch['from_bus']
    	to_bus = branch['to_bus']

    	return -model.dva[(from_bus, to_bus)] + sum(model.dva_branch[branch_name, i, j] for i in model.box_index_set) >= -math.pi*(1-model.u[branch_name])

    model.delta_branch_lb_Constr = pe.Constraint(branch_name_set, model.power_type_set, rule=delta_branch_lb_rule)

    #(7) - Constraints that force dva variable to be in only one interval

    #Upper bound

    def delta_branch_box_ub_rule(model, branch_name, i, j):
    	if j==0:
    		delta_ub = branch_dict["Active_from_bus"][branch_name]['boxes']['coords'][i-1][7][2]
    	else:
    		delta_ub = branch_dict["Reactive_from_bus"][branch_name]['boxes']['coords'][i-1][7][2]
    	return model.dva_branch[branch_name, i, j] <= delta_ub*model.u_branch[branch_name, i, j]

    model.delta_branch_box_ub_Constr = pe.Constraint(branch_name_set, model.box_index_set, model.power_type_set, rule=delta_branch_box_ub_rule)

    def delta_branch_box_lb_rule(model, branch_name, i, j):
    	if j==0:
    		delta_lb = branch_dict["Active_from_bus"][branch_name]['boxes']['coords'][i-1][0][2]
    	else:
    		delta_lb = branch_dict["Reactive_from_bus"][branch_name]['boxes']['coords'][i-1][0][2]
    	return model.dva_branch[branch_name, i, j] >= delta_lb*model.u_branch[branch_name, i, j]

    model.delta_branch_box_lb_Constr = pe.Constraint(branch_name_set, model.box_index_set, model.power_type_set, rule=delta_branch_box_lb_rule)

    #(8) - Approximating power flow equation by PWL approximation



    #Active_from_bus
    def pwl_active_from_ub_rule(model, branch_name, i):
    	branch = branches[branch_name]

    	from_bus = branch['from_bus']
    	to_bus = branch['to_bus']

    	g = tx_calc.calculate_conductance(branch)
    	b = tx_calc.calculate_susceptance(branch)
    	coeffs = branch_dict["Active_from_bus"][branch_name]['boxes']['coefficients'][i-1]
    	#M = 10*(g+b) + 4*(coeffs[0]+coeffs[1]+coeffs[2]+coeffs[3])
    	M = 2*s_max[branch_name] + 10*(np.abs(coeffs[0])+np.abs(coeffs[1])+np.abs(coeffs[2])+np.abs(coeffs[3]))
    	return -model.pf[branch_name] + coeffs[0]*model.vm[from_bus] + coeffs[1]*model.vm[to_bus] + coeffs[2]*model.dva_branch[branch_name, i, 0] + coeffs[3] <= M*(1-model.u_branch[branch_name, i, 0])

    model.pwl_active_from_ub_Constr = pe.Constraint(branch_name_set, model.box_index_set, rule=pwl_active_from_ub_rule)

    def pwl_active_from_lb_rule(model, branch_name, i):
    	branch = branches[branch_name]

    	from_bus = branch['from_bus']
    	to_bus = branch['to_bus']

    	g = tx_calc.calculate_conductance(branch)
    	b = tx_calc.calculate_susceptance(branch)

    	coeffs = branch_dict["Active_from_bus"][branch_name]['boxes']['coefficients'][i-1]
    	#M = -(10*(g+b) + 4*(coeffs[0]+coeffs[1]+coeffs[2]+coeffs[3]))
    	M = -2*s_max[branch_name] - 10*(np.abs(coeffs[0])+np.abs(coeffs[1])+np.abs(coeffs[2])+np.abs(coeffs[3]))
    	return -model.pf[branch_name] + coeffs[0]*model.vm[from_bus] + coeffs[1]*model.vm[to_bus] + coeffs[2]*model.dva_branch[branch_name, i, 0] + coeffs[3] >= M*(1-model.u_branch[branch_name, i, 0])

    model.pwl_active_from_lb_Constr = pe.Constraint(branch_name_set, model.box_index_set, rule=pwl_active_from_lb_rule)

    #Active_to_bus
    def pwl_active_to_ub_rule(model, branch_name, i):
    	branch = branches[branch_name]

    	from_bus = branch['from_bus']
    	to_bus = branch['to_bus']

    	g = tx_calc.calculate_conductance(branch)
    	b = tx_calc.calculate_susceptance(branch)

    	coeffs = branch_dict["Active_to_bus"][branch_name]['boxes']['coefficients'][i-1]
    	#M = 10*(g+b) + 4*(coeffs[0]+coeffs[1]+coeffs[2]+coeffs[3])
    	M = 2*s_max[branch_name] + 10*(np.abs(coeffs[0])+np.abs(coeffs[1])+np.abs(coeffs[2])+np.abs(coeffs[3]))
    	return -model.pt[branch_name] + coeffs[0]*model.vm[from_bus] + coeffs[1]*model.vm[to_bus] + coeffs[2]*model.dva_branch[branch_name, i, 0] + coeffs[3] <= M*(1-model.u_branch[branch_name, i, 0])

    model.pwl_active_to_ub_Constr = pe.Constraint(branch_name_set, model.box_index_set, rule=pwl_active_to_ub_rule)

    def pwl_active_to_lb_rule(model, branch_name, i):
    	branch = branches[branch_name]

    	from_bus = branch['from_bus']
    	to_bus = branch['to_bus']

    	g = tx_calc.calculate_conductance(branch)
    	b = tx_calc.calculate_susceptance(branch)

    	coeffs = branch_dict["Active_to_bus"][branch_name]['boxes']['coefficients'][i-1]
    	#M = -(10*(g+b) + 4*(coeffs[0]+coeffs[1]+coeffs[2]+coeffs[3]))
    	M = -2*s_max[branch_name] - 10*(np.abs(coeffs[0])+np.abs(coeffs[1])+np.abs(coeffs[2])+np.abs(coeffs[3]))
    	return -model.pt[branch_name] + coeffs[0]*model.vm[from_bus] + coeffs[1]*model.vm[to_bus] + coeffs[2]*model.dva_branch[branch_name, i, 0] + coeffs[3] >= M*(1-model.u_branch[branch_name, i, 0])

    model.pwl_active_to_lb_Constr = pe.Constraint(branch_name_set, model.box_index_set, rule=pwl_active_to_lb_rule)

    #Reactive_from_bus

    def pwl_reactive_from_ub_rule(model, branch_name, i):
    	branch = branches[branch_name]

    	from_bus = branch['from_bus']
    	to_bus = branch['to_bus']

    	g = tx_calc.calculate_conductance(branch)
    	b = tx_calc.calculate_susceptance(branch)

    	coeffs = branch_dict["Reactive_from_bus"][branch_name]['boxes']['coefficients'][i-1]
    	#M = 10*(g+b) + 4*(coeffs[0]+coeffs[1]+coeffs[2]+coeffs[3])
    	M = 2*s_max[branch_name] + 10*(np.abs(coeffs[0])+np.abs(coeffs[1])+np.abs(coeffs[2])+np.abs(coeffs[3]))
    	return -model.qf[branch_name] + coeffs[0]*model.vm[from_bus] + coeffs[1]*model.vm[to_bus] + coeffs[2]*model.dva_branch[branch_name, i, 1] + coeffs[3] <= M*(1-model.u_branch[branch_name, i, 1])

    model.pwl_reactive_from_ub_Constr = pe.Constraint(branch_name_set, model.box_index_set, rule=pwl_reactive_from_ub_rule)

    def pwl_reactive_from_lb_rule(model, branch_name, i):
    	branch = branches[branch_name]

    	from_bus = branch['from_bus']
    	to_bus = branch['to_bus']

    	g = tx_calc.calculate_conductance(branch)
    	b = tx_calc.calculate_susceptance(branch)

    	coeffs = branch_dict["Reactive_from_bus"][branch_name]['boxes']['coefficients'][i-1]
    	#M = -(10*(g+b) + 4*(coeffs[0]+coeffs[1]+coeffs[2]+coeffs[3]))
    	M = -2*s_max[branch_name] - 10*(np.abs(coeffs[0])+np.abs(coeffs[1])+np.abs(coeffs[2])+np.abs(coeffs[3]))
    	return -model.qf[branch_name] + coeffs[0]*model.vm[from_bus] + coeffs[1]*model.vm[to_bus] + coeffs[2]*model.dva_branch[branch_name, i, 1] + coeffs[3] >= M*(1-model.u_branch[branch_name, i, 1])

    model.pwl_reactive_from_lb_Constr = pe.Constraint(branch_name_set, model.box_index_set, rule=pwl_reactive_from_lb_rule)

    #Reactive_to_bus

    def pwl_reactive_to_ub_rule(model, branch_name, i):
    	branch = branches[branch_name]

    	from_bus = branch['from_bus']
    	to_bus = branch['to_bus']

    	g = tx_calc.calculate_conductance(branch)
    	b = tx_calc.calculate_susceptance(branch)

    	coeffs = branch_dict["Reactive_to_bus"][branch_name]['boxes']['coefficients'][i-1]
    	#M = 10*(g+b) + 4*(coeffs[0]+coeffs[1]+coeffs[2]+coeffs[3])
    	M = 2*s_max[branch_name] + 10*(np.abs(coeffs[0])+np.abs(coeffs[1])+np.abs(coeffs[2])+np.abs(coeffs[3]))
    	return -model.qt[branch_name] + coeffs[0]*model.vm[from_bus] + coeffs[1]*model.vm[to_bus] + coeffs[2]*model.dva_branch[branch_name, i, 1] + coeffs[3] <= M*(1-model.u_branch[branch_name, i, 1])

    model.pwl_reactive_to_ub_Constr = pe.Constraint(branch_name_set, model.box_index_set, rule=pwl_reactive_to_ub_rule)

    def pwl_reactive_to_lb_rule(model, branch_name, i):
    	branch = branches[branch_name]

    	from_bus = branch['from_bus']
    	to_bus = branch['to_bus']

    	g = tx_calc.calculate_conductance(branch)
    	b = tx_calc.calculate_susceptance(branch)

    	coeffs = branch_dict["Reactive_to_bus"][branch_name]['boxes']['coefficients'][i-1]
    	#M = -(10*(g+b) + 4*(coeffs[0]+coeffs[1]+coeffs[2]+coeffs[3]))
    	M = -2*s_max[branch_name] - 10*(np.abs(coeffs[0])+np.abs(coeffs[1])+np.abs(coeffs[2])+np.abs(coeffs[3]))
    	return -model.qt[branch_name] + coeffs[0]*model.vm[from_bus] + coeffs[1]*model.vm[to_bus] + coeffs[2]*model.dva_branch[branch_name, i, 1] + coeffs[3] >= M*(1-model.u_branch[branch_name, i, 1])

    model.pwl_reactive_to_lb_Constr = pe.Constraint(branch_name_set, model.box_index_set, rule=pwl_reactive_to_lb_rule)

    
    ### declare the pq balances
    libbus.declare_eq_p_balance(model=model,
                                index_set=bus_attrs['names'],
                                bus_p_loads=bus_p_loads,
                                gens_by_bus=gens_by_bus,
                                bus_gs_fixed_shunts=bus_gs_fixed_shunts,
                                inlet_branches_by_bus=inlet_branches_by_bus,
                                outlet_branches_by_bus=outlet_branches_by_bus,
                                **p_rhs_kwargs
                                )

    libbus.declare_eq_q_balance(model=model,
                                index_set=bus_attrs['names'],
                                bus_q_loads=bus_q_loads,
                                gens_by_bus=gens_by_bus,
                                bus_bs_fixed_shunts=bus_bs_fixed_shunts,
                                inlet_branches_by_bus=inlet_branches_by_bus,
                                outlet_branches_by_bus=outlet_branches_by_bus,
                                **q_rhs_kwargs
                                )

    ### declare the thermal limits
    libbranch.declare_ineq_s_branch_thermal_limit(model=model,
                                                  index_set=branch_attrs['names'],
                                                  branches=branches,
                                                  s_thermal_limits=s_max,
                                                  flow_type=FlowType.POWER
                                                  )

    # declare angle difference limits on interconnected buses
    # libbranch.declare_ineq_angle_diff_branch_lbub_c_s(model=model,
    #                                                   index_set=branch_attrs['names'],
    #                                                   branches=branches
    #                                                   )

    ### declare the generator cost objective
    libgen.declare_expression_pgqg_operating_cost(model=model,
                                                  index_set=gen_attrs['names'],
                                                  p_costs=gen_attrs['p_cost'],
                                                  q_costs=gen_attrs.get('q_cost', None)
                                                  )

    obj_expr = sum(model.pg_operating_cost[gen_name] for gen_name in model.pg_operating_cost)
    if include_feasibility_slack:
        obj_expr += penalty_expr
    if hasattr(model, 'qg_operating_cost'):
        obj_expr += sum(model.qg_operating_cost[gen_name] for gen_name in model.qg_operating_cost)

    model.obj = pe.Objective(expr=obj_expr)

    return model, md