Ejemplo n.º 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
Ejemplo n.º 2
0
def _copperplate_network_model(block, tm, relax_balance=None):

    m, gens_by_bus, bus_p_loads, bus_gs_fixed_shunts = \
            _setup_egret_network_model(block, tm)

    ### 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,
                                   relax_balance = relax_balance,
                                   )
Ejemplo n.º 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,
                                   )
Ejemplo n.º 4
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
Ejemplo n.º 5
0
def _ptdf_dcopf_network_model(block, tm):
    m, gens_by_bus, bus_p_loads, bus_gs_fixed_shunts = \
            _setup_egret_network_model(block, tm)

    buses, branches, \
    branches_in_service, branches_out_service, \
    interfaces, contingencies = _setup_egret_network_topology(m, tm)

    ptdf_options = m._ptdf_options

    libbus.declare_var_p_nw(block, m.Buses)

    ### declare net withdraw expression for use in PTDF power flows
    libbus.declare_eq_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,
    )

    _setup_branch_slacks(m, block, tm)

    ### interface setup
    libbranch.declare_expr_pfi(model=block, index_set=interfaces.keys())

    _setup_interface_slacks(m, block, tm)

    ### contingency setup
    ### NOTE: important that this not be dense, we'll add elements
    ###       as we find violations
    block._contingency_set = Set(within=m.Contingencies * m.TransmissionLines)
    block.pfc = Expression(block._contingency_set)
    _setup_contingency_slacks(m, block, tm)

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

        reference_bus = value(m.ReferenceBus)

        ## NOTE: For now, just use a flat-start for unit commitment
        PTDF = ptdf_utils.VirtualPTDFMatrix(branches,
                                            buses,
                                            reference_bus,
                                            BasePointType.FLATSTART,
                                            ptdf_options,
                                            contingencies=contingencies,
                                            branches_keys=branches_in_service,
                                            buses_keys=buses_idx,
                                            interfaces=interfaces)

        m._PTDFs[branches_out_service] = PTDF

    else:
        PTDF = m._PTDFs[branches_out_service]

    ### attach the current PTDF object to this block
    block._PTDF = PTDF
    rel_ptdf_tol = m._ptdf_options['rel_ptdf_tol']
    abs_ptdf_tol = m._ptdf_options['abs_ptdf_tol']

    if ptdf_options['lazy']:
        ### add "blank" real power flow limits
        libbranch.declare_ineq_p_branch_thermal_bounds(
            model=block,
            index_set=branches_in_service,
            branches=branches,
            p_thermal_limits=None,
            approximation_type=None,
            slacks=True,
            slack_cost_expr=m.BranchViolationCost[tm])
        ### declare the "blank" interface flow limits
        libbranch.declare_ineq_p_interface_bounds(
            model=block,
            index_set=interfaces.keys(),
            interfaces=interfaces,
            approximation_type=None,
            slacks=True,
            slack_cost_expr=m.InterfaceViolationCost[tm])
        ### declare the "blank" interface flow limits
        libbranch.declare_ineq_p_contingency_branch_thermal_bounds(
            model=block,
            index_set=block._contingency_set,
            pc_thermal_limits=None,
            approximation_type=None,
            slacks=True,
            slack_cost_expr=m.ContingencyViolationCost[tm])

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

        ### add initial branches to monitored set
        lpu.add_initial_monitored_branches(block, branches,
                                           branches_in_service, ptdf_options,
                                           PTDF)

        ### add initial interfaces to monitored set
        lpu.add_initial_monitored_interfaces(block, interfaces, ptdf_options,
                                             PTDF)

    else:  ### add all the dense constraints
        if contingencies:
            raise RuntimeError(
                "Contingency constraints only supported in lazy mode")
        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_bounds(
            model=block,
            index_set=branches_in_service,
            branches=branches,
            p_thermal_limits=p_max,
            approximation_type=ApproximationType.PTDF,
            slacks=True,
            slack_cost_expr=m.BranchViolationCost[tm])

        ### declare the branch power flow approximation constraints
        libbranch.declare_eq_interface_power_ptdf_approx(
            model=block,
            index_set=interfaces.keys(),
            PTDF=PTDF,
            abs_ptdf_tol=abs_ptdf_tol,
            rel_ptdf_tol=rel_ptdf_tol)

        ### declare the interface flow limits
        libbranch.declare_ineq_p_interface_bounds(
            model=block,
            index_set=interfaces.keys(),
            interfaces=interfaces,
            approximation_type=ApproximationType.PTDF,
            slacks=True,
            slack_cost_expr=m.InterfaceViolationCost[tm])
Ejemplo n.º 6
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
Ejemplo n.º 7
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)
Ejemplo n.º 8
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
Ejemplo n.º 9
0
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
Ejemplo n.º 10
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
Ejemplo n.º 11
0
def _ptdf_dcopf_network_model(block, tm):
    m, gens_by_bus, bus_p_loads, bus_gs_fixed_shunts = \
            _setup_egret_network_model(block, tm)

    buses, branches, branches_in_service, branches_out_service, interfaces = \
            _setup_egret_network_topology(m, tm)

    ptdf_options = m._ptdf_options

    libbus.declare_var_p_nw(block, m.Buses)

    ### declare net withdraw expression for use in PTDF power flows
    libbus.declare_eq_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,
    )

    ### interface setup
    libbranch.declare_expr_pfi(model=block, index_set=interfaces.keys())

    _setup_interface_slacks(m, block, tm)

    ### 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,
                                                         interfaces=interfaces)

        ## 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,
                                         ptdf_options,
                                         branches_keys=branches_in_service,
                                         buses_keys=buses_idx,
                                         interfaces=interfaces)

        m._PTDFs[branches_out_service] = PTDF

    else:
        PTDF = m._PTDFs[branches_out_service]

    ### attach the current PTDF object to this block
    block._PTDF = PTDF
    rel_ptdf_tol = m._ptdf_options['rel_ptdf_tol']
    abs_ptdf_tol = m._ptdf_options['abs_ptdf_tol']

    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,
        )
        ### add helpers for tracking monitored branches
        lpu.add_monitored_branch_tracker(block)

    else:  ### add all the dense constraints
        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)

    ## for now, just add all the interface constraints
    ## TODO: incorporate into lazy logic
    ### declare the branch power flow approximation constraints
    libbranch.declare_eq_interface_power_ptdf_approx(
        model=block,
        index_set=interfaces.keys(),
        PTDF=PTDF,
        abs_ptdf_tol=abs_ptdf_tol,
        rel_ptdf_tol=rel_ptdf_tol)

    ### declare the interface flow limits
    libbranch.declare_ineq_p_interface_lbub(
        model=block,
        index_set=interfaces.keys(),
        interfaces=interfaces,
    )