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
def _btheta_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) if contingencies: raise RuntimeError( "Contingency constraints only supported in lazy-PTDF mode") ## 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) 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, ) _setup_branch_slacks(m, block, tm) ### 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, slacks=True, slack_cost_expr=m.BranchViolationCost[tm]) ### 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) ### interface model ### declare the interface variables libbranch.declare_var_pfi( model=block, index_set=interfaces.keys(), ) _setup_interface_slacks(m, block, tm) ### declare the interface flow equality constraint libbranch.declare_eq_interface_power_btheta_approx( model=block, index_set=interfaces.keys(), interfaces=interfaces, ) ### declare the interface flow limits libbranch.declare_ineq_p_interface_bounds( model=block, index_set=interfaces.keys(), interfaces=interfaces, slacks=True, slack_cost_expr=m.InterfaceViolationCost[tm]) return block
def create_relaxation_of_polar_acopf(model_data, include_soc=True, use_linear_relaxation=False): if not coramin_available: raise ImportError( 'Cannot create polar relaxation unless coramin is available.') model, md = _create_base_relaxation(model_data) branches = dict(md.elements(element_type='branch')) bus_attrs = md.attributes(element_type='bus') branch_attrs = md.attributes(element_type='branch') 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()) # 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'])) 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'] ref_angle = md.data['system']['reference_bus_angle'] model.va[ref_bus].fix(radians(ref_angle)) # relate c, s, and vmsq to vm and va libbus.declare_eq_vmsq(model=model, index_set=bus_attrs['names'], coordinate_type=CoordinateType.POLAR) libbranch.declare_eq_c(model=model, index_set=unique_bus_pairs, coordinate_type=CoordinateType.POLAR) libbranch.declare_eq_s(model=model, index_set=unique_bus_pairs, 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) fbbt(model, deactivate_satisfied_constraints=False) model = coramin.relaxations.relax(model, in_place=True, use_fbbt=False) if not use_linear_relaxation: for b in model.component_data_objects(pe.Block, descend_into=True, active=True, sort=True): if isinstance(b, (coramin.relaxations.BaseRelaxation, coramin.relaxations.BaseRelaxationData)): if polynomial_degree(b.get_rhs_expr()) == 2: if not isinstance( b, (coramin.relaxations.PWMcCormickRelaxation, coramin.relaxations.PWMcCormickRelaxationData)): b.use_linear_relaxation = False b.rebuild() if include_soc: libbranch.declare_ineq_soc( model=model, index_set=unique_bus_pairs, use_outer_approximation=use_linear_relaxation) return model, md
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_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
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
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
def create_explicit_subproblem(model, subproblem, model_data, include_angle_diff_limits=False, include_bigm=False): ### power system data md = model_data ### create dictionaries of object sets 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')) ### create dictionaries across object attributes for an object of the same set type 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) ### 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.) ### declare load shed variables decl.declare_var('load_shed', subproblem, buses_with_loads, initialize=0.0, domain=pe.NonNegativeReals) #libbus.declare_var_pl(model.subproblem, bus_attrs['names'], initialize=bus_p_loads) #model.subproblem.pl.fix() subproblem.pl = bus_p_loads ### 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']} va_init = {k: bus_attrs['va'][k] * (pi / 180) for k in bus_attrs['va']} libbus.declare_var_va(subproblem, bus_attrs['names'], initialize=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'] 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(subproblem, gen_attrs['names'], initialize=pg_init) ### 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'] } 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=subproblem, index_set=branch_attrs['names'], initialize=pf_init) # need to include variable references on subproblem to variables, which exist on the master block #bi.components.varref(subproblem, origin = model) subproblem.add_component("u", Reference(model.u)) subproblem.add_component("v", Reference(model.v)) subproblem.add_component("w", Reference(model.w)) if include_bigm: # create big-M _create_bigm(subproblem, md) ### declare the branch power flow disjuncts subcons.declare_eq_branch_power_btheta_approx_bigM( model=subproblem, index_set=branch_attrs['names'], branches=branches) ### declare the real power flow limits p_max = {k: branches[k]['rating_long_term'] for k in branches.keys()} subcons.declare_ineq_p_branch_thermal_lbub_switch( model=subproblem, index_set=branch_attrs['names'], p_thermal_limits=p_max) else: ### declare the branch power flow with indicator variable in the bilinear term subcons.declare_eq_branch_power_btheta_approx_nonlin( model=subproblem, index_set=branch_attrs['names'], branches=branches) ### declare the real power flow limits p_max = {k: branches[k]['rating_long_term'] for k in branches.keys()} libbranch.declare_ineq_p_branch_thermal_lbub( model=subproblem, index_set=branch_attrs['names'], branches=branches, p_thermal_limits=p_max, approximation_type=ApproximationType.BTHETA) ### declare the load shed subcons.declare_ineq_load_shed(model=subproblem, index_set=buses_with_loads) ### declare the generator compromised subcons.declare_ineq_gen(model=subproblem, index_set=gen_attrs['names'], gens=gens) ### declare the p balance rhs_kwargs = {'include_feasibility_slack_neg': 'load_shed'} libbus.declare_eq_p_balance_dc_approx( 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 angle difference limits on interconnected buses if include_angle_diff_limits: libbranch.declare_ineq_angle_diff_branch_lbub( model=subproblem, index_set=branch_attrs['names'], branches=branches, coordinate_type=CoordinateType.POLAR) ### lower-level objective for interdiction problem (opposite to upper-level objective) subproblem.obj = pe.Objective(expr=sum(subproblem.load_shed[l] for l in buses_with_loads), sense=pe.minimize) return model, md
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
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
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
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