Julia OPF API (eDisGo_OPF)
Note
This page is generated automatically from the docstrings in the eDisGo_OPF
Julia source (edisgo/opf/eDisGo_OPF.jl/src/). Only documented symbols are
listed, so the reference fills in on its own as docstrings are added at the
source.
The optimal power flow (OPF) is implemented in Julia, in the eDisGo_OPF
package, which extends
PowerModels.jl with a branch-flow
formulation for distribution grids and eDisGo’s flexibilities (storage,
electromobility, heat pumps, demand-side management, curtailment).
From Python the OPF is run via pm_optimize(), which
serialises the grid and flexibility data to JSON, hands it to eDisGo_OPF and
reads the results back. For the modelling background — branch-flow physics, the
SOC vs. non-convex relaxations and the opf_version variants — see
Multi-period optimal power flow.
The three exported problem formulations are BFPowerModelEdisgo (base
branch-flow), SOCBFPowerModelEdisgo (second-order-cone relaxation, convex) and
NCBFPowerModelEdisgo (non-convex, exact).
Problem formulations
Source: edisgo/opf/eDisGo_OPF.jl/src/core/types.jl
AbstractBFModelEdisgo
abstract type AbstractBFModelEdisgo <: AbstractBFQPModel
Abstract supertype for all eDisGo branch-flow OPF models. Concrete subtypes
(BFPowerModelEdisgo, SOCBFPowerModelEdisgo, NCBFPowerModelEdisgo) select how
the branch-flow equations are treated (base, second-order-cone relaxation, or
non-convex/exact).
BFPowerModelEdisgo
mutable struct BFPowerModelEdisgo <: AbstractBFModelEdisgo
Base radial branch-flow model for the eDisGo OPF — the eDisGo extension of
PowerModels’ branch-flow (DistFlow) formulation. Applicable to problem
formulations whose name ends in _bf (e.g. build_mn_opf_bf_flex).
The branch-flow model is the natural formulation for the tree-shaped (radial)
distribution grids eDisGo works with. For every branch i → j it couples the
sending-end active and reactive power (P, Q), the squared branch current ccm
(= I²) and the squared bus voltages w (= V²), together with a nodal power
balance at each bus, thermal/current limits, voltage limits and the flexibility
power/energy bands. The defining coupling between power, current and voltage is
the quadratic relation P² + Q² = V²·I², which is what makes an exact AC OPF
non-convex.
This type carries the shared model structure; how that quadratic coupling is
enforced is fixed by the concrete subtypes SOCBFPowerModelEdisgo (convex
relaxation) and NCBFPowerModelEdisgo (exact, non-convex) — one of those is what
you actually solve. All quantities are in per-unit on the common base power
s_base.
SOCBFPowerModelEdisgo
mutable struct SOCBFPowerModelEdisgo <: AbstractSOCBFModelEdisgo
Second-order-cone (SOC) relaxation of the radial branch-flow model. Applicable to
problem formulations whose name ends in _bf.
The non-convex coupling P² + Q² = V²·I² is relaxed to the convex inequality
P² + Q² ≤ V²·I² — a second-order cone (see constraint_model_current for
AbstractSOCBFModelEdisgo). This turns the OPF into a convex program, solved with
Gurobi: fast, reliable and globally optimal. For radial grids the relaxation is
usually exact — the inequality is tight at the optimum, so the solution is also
feasible for the original AC problem. check_SOC_equality flags any branches and
time steps where it is not tight; there, running with warm_start=true recovers a
feasible AC solution by polishing with the non-convex model
(NCBFPowerModelEdisgo). This is the model behind the default method="soc".
NCBFPowerModelEdisgo
mutable struct NCBFPowerModelEdisgo <: AbstractNCBFModelEdisgo
Non-convex (NC), exact radial branch-flow model. Applicable to problem
formulations whose name ends in _bf.
Keeps the exact quadratic equality P² + Q² = V²·I² (added as a nonlinear
@NLconstraint; see constraint_model_current for AbstractNCBFModelEdisgo), so
no relaxation is involved. The resulting non-convex program is solved with the
Ipopt interior-point solver: more accurate in principle, but slower and only
guaranteed to find a local optimum. Selected via method="nc" (cold start), or
used automatically as the warm-started polishing step when method="soc" is run
with warm_start=true, starting from the exact Gurobi SOC solution.
Problem definition & build
Source: edisgo/opf/eDisGo_OPF.jl/src/prob/opf_bf.jl
solve_mn_opf_bf_flex
function solve_mn_opf_bf_flex(file, model_type::Type{T}, optimizer; kwargs...) where T <: AbstractBFModel
Solve multinetwork branch flow OPF with multiple flexibilities
build_mn_opf_bf_flex
function build_mn_opf_bf_flex(pm::AbstractBFModelEdisgo)
Build multinetwork branch flow OPF with multiple flexibilities
Model setup
Source: edisgo/opf/eDisGo_OPF.jl/src/core/base.jl
solve_model
function solve_model(data::Dict{String,<:Any}, model_type::Type, optimizer, build_method;
ref_extensions=[], solution_processors=[], relax_integrality=false,
multinetwork=false, multiconductor=false, kwargs...)
Instantiate and solve an eDisGo OPF model.
Builds a model of type model_type from the network data using build_method
(e.g. build_mn_opf_bf_flex), optimises it with the given JuMP optimizer
(Gurobi or Ipopt), and returns the tuple (result, pm), where result is the
PowerModels solution dict and pm is the constructed model object. The keyword
arguments mirror PowerModels’ solve_model/instantiate_model (ref_extensions,
solution_processors, relax_integrality, multinetwork, multiconductor).
instantiate_model
function instantiate_model(data::Dict{String,<:Any}, model_type::Type, build_method; kwargs...)
Instantiate an eDisGo OPF model without solving it — a thin wrapper around
InfrastructureModels.instantiate_model with eDisGo’s ref_add_core! reference
extension and the global keys. Used internally by solve_model.
ref_add_core!
function ref_add_core!(ref::Dict{Symbol,Any})
Returns a dict that stores commonly used pre-computed data from of the data dictionary, primarily for converting data-types, filtering out deactivated components, and storing system-wide values that need to be computed globally.
Some of the common keys include:
:off_angminand:off_angmax(seecalc_theta_delta_bounds(data)),:bus– the set{(i, bus) in ref[:bus] : bus["bus_type"] != 4},:gen– the set{(i, gen) in ref[:gen] : gen["gen_status"] == 1 && gen["gen_bus"] in keys(ref[:bus])},:branch– the set of branches that are active in the network (based on the component status values),:arcs_from– the set[(i,b["f_bus"],b["t_bus"]) for (i,b) in ref[:branch]],:arcs_to– the set[(i,b["t_bus"],b["f_bus"]) for (i,b) in ref[:branch]],:arcs– the set of arcs from botharcs_fromandarcs_to,:bus_arcs– the mappingDict(i => [(l,i,j) for (l,i,j) in ref[:arcs]]),:bus_arcs_to– the mappingDict(j => [(l,i,j) for (l,i,j) in ref[:arcs_from]]),:bus_arcs_from– the mappingDict(i => [(l,i,j) for (l,i,j) in ref[:arcs_from]]),:bus_lines_to– the mappingDict(j => [l for (l,i,j) in ref[:arcs_from]]),:buspairs– (seebuspair_parameters(ref[:arcs_from], ref[:branch], ref[:bus])),:bus_gens– the mappingDict(i => [gen["gen_bus"] for (i,gen) in ref[:gen]]).:bus_gens_nd– the mappingDict(i => [gen_nd["gen_bus"] for (i,gen) in ref[:gen_nd]]).:bus_gens_slack– the mappingDict(i => [gen_slack["gen_bus"] for (i,gen) in ref[:gen_slack]]).:bus_loads– the mappingDict(i => [load["load_bus"] for (i,load) in ref[:load]]).:bus_shunts– the mappingDict(i => [shunt["shunt_bus"] for (i,shunt) in ref[:shunt]]).:bus_dsm– the mappingDict(i => [dsm["dsm_bus"] for (i,dsm) in ref[:dsm]]).:bus_cps– the mappingDict(i => [cp["cp_bus"] for (i,cp) in ref[:electromobility]]).:bus_hps– the mappingDict(i => [hp["hp_bus"] for (i,hp) in ref[:heatpumps]]).:arcs_from_dc– the set[(i,b["f_bus"],b["t_bus"]) for (i,b) in ref[:dcline]],:arcs_to_dc– the set[(i,b["t_bus"],b["f_bus"]) for (i,b) in ref[:dcline]],:arcs_dc– the set of arcs from botharcs_from_dcandarcs_to_dc,:bus_arcs_dc– the mappingDict(i => [(l,i,j) for (l,i,j) in ref[:arcs_dc]]), and:buspairs_dc– (seebuspair_parameters(ref[:arcs_from_dc], ref[:dcline], ref[:bus])),
If :ne_branch exists, then the following keys are also available with similar semantics:
:ne_branch,:ne_arcs_from,:ne_arcs_to,:ne_arcs,:ne_bus_arcs,:ne_buspairs.
Added keys for eDisGo OPF include:
:bus_arcs_to– the mappingDict(j => [(l,i,j) for (l,i,j) in ref[:arcs_from]]),:bus_arcs_from– the mappingDict(i => [(l,i,j) for (l,i,j) in ref[:arcs_from]]),:bus_lines_to– the mappingDict(j => [l for (l,i,j) in ref[:arcs_from]]),:bus_gens_nd– the mappingDict(i => [gen_nd["gen_bus"] for (i,gen) in ref[:gen_nd]]).:bus_gens_slack– the mappingDict(i => [gen_slack["gen_bus"] for (i,gen) in ref[:gen_slack]]).:bus_dsm– the mappingDict(i => [dsm["dsm_bus"] for (i,dsm) in ref[:dsm]]).:bus_cps– the mappingDict(i => [cp["cp_bus"] for (i,cp) in ref[:electromobility]]).:bus_hps– the mappingDict(i => [hp["hp_bus"] for (i,hp) in ref[:heatpumps]]).
Variables
Source: edisgo/opf/eDisGo_OPF.jl/src/core/variables.jl
variable_branch_power_radial
function variable_branch_power_radial(pm::AbstractPowerModel; kwargs...)
Create the branch power-flow variables for the radial branch-flow model: both the
active (p) and reactive (q) flow on every branch. Wrapper around
variable_branch_power_real_radial and variable_branch_power_imaginary_radial.
variable_branch_power_real_radial
function variable_branch_power_real_radial(pm::AbstractPowerModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
variable: p[l,i,j] for (l,i,j) in arcs_from
variable_branch_power_imaginary_radial
function variable_branch_power_imaginary_radial(pm::AbstractPowerModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
variable: q[l,i,j] for (l,i,j) in arcs
variable_bus_voltage_magnitude_sqr
function variable_bus_voltage_magnitude_sqr(pm::AbstractPowerModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
Variable w[i] for each non-storage bus i: the squared voltage magnitude
(= V²), bounded by vmin²/vmax².
variable_max_line_loading
function variable_max_line_loading(pm::AbstractPowerModel; kwargs...)
Create the maximum-line-loading variable ll (wrapper around
variable_line_loading_max), used by the line-loading-minimising objectives
(opf_version 1 and 3).
variable_line_loading_max
function variable_line_loading_max(pm::AbstractPowerModel; nw::Int=nw_id_default, report::Bool=true)
variable: ll[l,i,j] for (l,i,j) in arcs_from
variable_gen_power_curt
function variable_gen_power_curt(pm::AbstractPowerModel; kwargs...)
generates variables for both active and reactive non-dispatchable power generation curtailment
variable_gen_power_curt_real
function variable_gen_power_curt_real(pm::AbstractPowerModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
variable: pgc[j] for j in gen_nd
variable_gen_power_curt_imaginary
function variable_gen_power_curt_imaginary(pm::AbstractPowerModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
variable: qgc[j] for j in gen_nd
variable_battery_storage
function variable_battery_storage(pm::AbstractPowerModel; kwargs...)
variables for modeling storage units, includes grid injection and internal variables
variable_battery_storage_power_real
function variable_battery_storage_power_real(pm::AbstractPowerModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
Variable ps[i] for i in storage: the active power of each battery storage
unit (charging/discharging), bounded by the unit’s pmin and pmax.
variable_battery_storage_power_imaginary
function variable_battery_storage_power_imaginary(pm::AbstractPowerModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
Variable qs[i] for i in storage: the reactive power of each battery storage
unit, bounded by the unit’s qmin and qmax. (Optional; by default reactive
storage power is derived from the power factor in the power-balance constraint.)
variable_dsm_storage_power
function variable_dsm_storage_power(pm::AbstractPowerModel; kwargs...)
variables for modeling dsm storage units, includes grid injection and internal variables
variable_dsm_storage_power_real
function variable_dsm_storage_power_real(pm::AbstractPowerModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
Variable pdsm[i] for i in dsm: the demand-side-management load-shift power
of each DSM unit, bounded by p_min/p_max.
variable_dsm_storage_power_imaginary
function variable_dsm_storage_power_imaginary(pm::AbstractPowerModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
Variable qdsm[i] for i in dsm: the reactive power of each DSM unit, bounded
by q_min/q_max. (Optional; by default derived from the power factor.)
variable_dsm_storage_energy
function variable_dsm_storage_energy(pm::AbstractPowerModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
Variable dsme[i] for i in dsm: the accumulated shifted energy of each DSM
unit, bounded by e_min/e_max. Coupled to pdsm over time by the DSM storage
constraints.
variable_heat_storage
function variable_heat_storage(pm::AbstractPowerModel; kwargs...)
variables for modeling heat storage units, includes grid injection and internal variables
variable_heat_storage_power
function variable_heat_storage_power(pm::AbstractPowerModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
Variable phs[i] for i in heat_storage: the (dis)charging thermal power of
each heat storage unit, bounded by ±capacity.
variable_heat_storage_energy
function variable_heat_storage_energy(pm::AbstractPowerModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
Variable hse[i] for i in heat_storage: the stored thermal energy (state of
charge) of each heat storage unit, between 0 and its capacity.
variable_heat_pump_power
function variable_heat_pump_power(pm::AbstractPowerModel; kwargs...)
variables for modeling heat pumps, includes grid injection and internal variables
variable_heat_pump_power_real
function variable_heat_pump_power_real(pm::AbstractPowerModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
Variable php[i] for i in heatpumps: the electrical power drawn by each heat
pump, bounded by p_min/p_max.
variable_heat_pump_power_imaginary
function variable_heat_pump_power_imaginary(pm::AbstractPowerModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
Variable qhp[i] for i in heatpumps: the reactive power of each heat pump,
bounded by q_min/q_max. (Optional; by default derived from the power factor.)
variable_cp_power
function variable_cp_power(pm::AbstractPowerModel; kwargs...)
variables for modeling charging points, includes grid injection and internal variables
variable_cp_power_real
function variable_cp_power_real(pm::AbstractPowerModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
Variable pcp[i] for i in electromobility: the charging power of each charging
park, bounded by p_min/p_max.
variable_cp_power_imaginary
function variable_cp_power_imaginary(pm::AbstractPowerModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
Variable qcp[i] for i in electromobility: the reactive power of each charging
park, bounded by q_min/q_max. (Optional; by default derived from the power
factor.)
variable_cp_energy
function variable_cp_energy(pm::AbstractPowerModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
Variable cpe[i] for i in electromobility: the accumulated charged energy of
each charging park, bounded by e_min/e_max (the flexibility band). Coupled to
pcp over time by the charging-point constraints.
variable_slack_grid_restrictions
function variable_slack_grid_restrictions(pm::AbstractBFModelEdisgo; kwargs...)
slack variables for grid restrictions
variable_slack_heat_pump_storage
function variable_slack_heat_pump_storage(pm::AbstractBFModelEdisgo; kwargs...)
Create the heat-pump / heat-storage operation slack variables (wrapper around
variable_hs_slack and variable_hp2_slack), which keep the heat-pump energy
balance feasible at a penalty.
variable_hs_slack
function variable_hs_slack(pm::AbstractBFModelEdisgo; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
heat storage slack variable
variable_hp2_slack
function variable_hp2_slack(pm::AbstractBFModelEdisgo; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
heat pump operation slack variable
variable_hp_slack
function variable_hp_slack(pm::AbstractBFModelEdisgo; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
heat pump slack variable
variable_load_slack
function variable_load_slack(pm::AbstractBFModelEdisgo; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
load slack variable
variable_gen_slack
function variable_gen_slack(pm::AbstractBFModelEdisgo; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
gen slack variable
variable_ev_slack
function variable_ev_slack(pm::AbstractBFModelEdisgo; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
EV slack variable
variable_slack_gen
function variable_slack_gen(pm::AbstractBFModelEdisgo; kwargs...)
slack generator variables
variable_slack_gen_real
function variable_slack_gen_real(pm::AbstractBFModelEdisgo; nw::Int=nw_id_default, report::Bool=true)
Variable pgs[i] for i in gen_slack: the active power of each slack generator
(the substation / feed-in node), left unbounded.
variable_slack_gen_imaginary
function variable_slack_gen_imaginary(pm::AbstractBFModelEdisgo; nw::Int=nw_id_default, report::Bool=true)
Variable qgs[i] for i in gen_slack: the reactive power of each slack
generator (the substation / feed-in node), left unbounded.
variable_slack_HV_requirements
function variable_slack_HV_requirements(pm::AbstractPowerModel; kwargs...)
slack variables for HV requirement constraints
variable_slack_HV_requirements_real
function variable_slack_HV_requirements_real(pm::AbstractPowerModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
Variable phvs[i] for i in HV_requirements: the active-power slack on each
overlying-grid (HV) flexibility requirement, allowing the dispatch requested by the
higher voltage level to be missed at a penalty (opf_version 3 and 4).
variable_slack_HV_requirements_imaginary
function variable_slack_HV_requirements_imaginary(pm::AbstractPowerModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
Variable qhvs[i] for i in HV_requirements: the reactive-power counterpart of
phvs. (Optional; not used by default.)
Constraints — flexibilities & HV requirements
Source: edisgo/opf/eDisGo_OPF.jl/src/core/constraint.jl
constraint_store_state_initial
function constraint_store_state_initial(pm::AbstractBFModelEdisgo, n::Int, i::Int, energy, charge_eff, discharge_eff, time_elapsed, kind, p_loss)
Initial-time-step state constraint for a storage kind ("storage" battery,
"heat_storage", or "dsm").
Sets the stored energy after the first time step from the unit’s initial state of charge and its (dis)charging power, and pins the final state of charge to the required end value — Eq. (3.9)/(3.10) for batteries, (3.22)/(3.23) for heat storage and (3.32)/(3.33) for DSM in the eDisGo OPF formulation.
constraint_store_state
function constraint_store_state(pm::AbstractBFModelEdisgo, n_1::Int, n_2::Int, i::Int, charge_eff, discharge_eff, time_elapsed, kind, p_loss)
Inter-time-step state-of-charge coupling for a storage kind between networks
n_1 and n_2: the stored energy in n_2 equals that in n_1 plus the energy
(dis)charged over the elapsed time — Eq. (3.10), (3.23), (3.33) of the eDisGo OPF
formulation. For heat storage the previous energy is reduced by the standing-loss
factor.
constraint_cp_state_initial
function constraint_cp_state_initial(pm::AbstractBFModelEdisgo, n::Int, i::Int, eta)
Initial-time-step state constraint for charging park i: sets the charged energy
after the first time step from the midpoint of the flexibility band
(e_min+e_max)/2 and the charging power, scaled by the charging efficiency eta
— Eq. (3.25) of the eDisGo OPF formulation.
constraint_cp_state
function constraint_cp_state(pm::AbstractBFModelEdisgo, n_1::Int, n_2::Int, i::Int, eta)
Inter-time-step energy coupling for charging park i between networks n_1 and
n_2: the charged energy in n_2 equals that in n_1 plus the energy charged
over the elapsed time (scaled by the efficiency eta) — Eq. (3.26). In the last
time step the energy is pinned back to the midpoint of the flexibility band
(Eq. (3.25)).
constraint_hp_operation
function constraint_hp_operation(pm::AbstractBFModelEdisgo, i::Int, nw::Int=nw_id_default)
Heat-pump energy balance for heat pump i in network nw: the electrical power
drawn (php, plus the operation slack phps2) times the coefficient of
performance cop must cover the heat demand pd plus the net heat-storage
(dis)charge (phss - phs) — Eq. (3.19) of the eDisGo OPF formulation.
constraint_HV_requirements
function constraint_HV_requirements(pm::AbstractBFModelEdisgo, i::Int, nw::Int=nw_id_default)
Overlying-grid requirement constraint i in network nw (opf_version 3 and 4):
forces the total dispatch of the addressed flexibility (DSM, curtailment, storage,
heat pumps or charging points) to meet the active power P requested by the higher
voltage level, up to the slack phvs.
Constraint templates
Source: edisgo/opf/eDisGo_OPF.jl/src/core/constraint_template.jl
constraint_power_balance_bf
function constraint_power_balance_bf(pm::AbstractBFModelEdisgo, i::Int; nw::Int=nw_id_default)
power balance for radial branch flow model
constraint_voltage_magnitude_difference_radial
function constraint_voltage_magnitude_difference_radial(pm::AbstractBFModelEdisgo, i::Int; nw::Int=nw_id_default)
Apply the branch-flow voltage-magnitude-difference equation for branch i in
network nw.
Relates the squared voltage magnitudes at the two ends of the branch to the active/reactive power flows and the squared current magnitude (Eq. (3.5) of the eDisGo OPF formulation). Virtual storage branches are skipped, as they do not represent a physical line.
constraint_store_state
function constraint_store_state(pm::AbstractBFModelEdisgo, i::Int; nw::Int=nw_id_default, kind::String)
First-time-step storage state constraint for unit i of type kind ("storage",
"heat_storage" or "dsm") in network nw. Looks up the unit’s parameters
(initial energy, charge/discharge efficiency, standing loss, elapsed time) and
forwards to constraint_store_state_initial — Eq. (3.9)/(3.22)/(3.32).
constraint_store_state
function constraint_store_state(pm::AbstractBFModelEdisgo, i::Int, nw_1::Int, nw_2::Int, kind::String)
Couple the state of charge of storage unit i of type kind between two
consecutive time steps (networks nw_1 and nw_2).
kind is one of "storage" (battery), "heat_storage" or "dsm". Links the
stored energy in nw_2 to that in nw_1 via the (dis)charging power and the
elapsed time (Eq. (3.10), (3.23), (3.33) of the eDisGo OPF formulation; heat
storage additionally accounts for standing losses). If the unit is inactive in
nw_1, the initial-state constraint is applied from nw_2’s data instead.
constraint_model_current
function constraint_model_current(pm::AbstractPowerModel; nw::Int=nw_id_default)
Template for the current/power/voltage coupling constraint: forwards to the
formulation-specific method for network nw — the convex second-order-cone
inequality (AbstractSOCBFModelEdisgo) or the exact nonlinear equality
(AbstractNCBFModelEdisgo).
Branch-flow formulation
Source: edisgo/opf/eDisGo_OPF.jl/src/form/bf.jl
variable_branch_current
function variable_branch_current(pm::AbstractBFModel; kwargs...)
Create the squared branch-current-magnitude variables for the branch-flow model
(wrapper around variable_buspair_current_magnitude_sqr, which defines ccm[i]).
variable_bus_voltage
function variable_bus_voltage(pm::AbstractBFModel; kwargs...)
Create the bus-voltage variable for the branch-flow model (wrapper around
variable_bus_voltage_magnitude_sqr, which defines w[i] = V²).
variable_buspair_current_magnitude_sqr
function variable_buspair_current_magnitude_sqr(pm::AbstractBFModel; nw::Int=nw_id_default, bounded::Bool=true, report::Bool=true)
Variable ccm[i] for each branch i: the squared branch current magnitude
(= I²). Lower-bounded by 0 and upper-bounded from the branch rating and the
sending-bus voltage ((rate_a·tap / vmin)²); in the unbounded model only storage
(virtual) branches receive the upper bound.
constraint_voltage_magnitude_difference
function constraint_voltage_magnitude_difference(pm::AbstractBFModelEdisgo, n::Int, i, f_bus, t_bus, f_idx, t_idx, r, x, tm)
Low-level branch-flow voltage-drop equation for branch i (network n): relates
the squared voltages at the two ends to the active/reactive flows, the squared
current ccm and the branch impedance r, x (with tap tm) — Eq. (3.5) of the
eDisGo OPF formulation. At the slack bus the squared voltage is fixed to 1 p.u.
Called by constraint_voltage_magnitude_difference_radial.
constraint_model_current
function constraint_model_current(pm::AbstractSOCBFModelEdisgo, n::Int) # Eq. (3.9)
Current/power/voltage coupling for the SOC (convex) branch-flow model in
network n: the second-order-cone inequality p² + q² ≤ (w/tm²)·ccm on every
branch — the convex relaxation (Eq. (3.6i) of the eDisGo OPF formulation) of the
exact equality.
constraint_model_current
function constraint_model_current(pm::AbstractNCBFModelEdisgo, n::Int) # Eq. (3.5)
Current/power/voltage coupling for the non-convex branch-flow model in network
n: the exact nonlinear equality p² + q² = (w/tm²)·ccm (a JuMP @NLconstraint)
on every non-storage branch — Eq. (3.6) of the eDisGo OPF formulation.
constraint_max_line_loading
function constraint_max_line_loading(pm::AbstractSOCBFModelEdisgo, n::Int)
Maximum-line-loading constraint for network n: bounds the squared apparent power
on every non-storage branch by the loading variable ll, (p² + q²)/s_nom² ≤ ll
— Eq. (3.40) of the eDisGo OPF formulation. Together with the line-loading
objective this minimises the worst-case loading (opf_version 1 and 3).
constraint_max_line_loading
function constraint_max_line_loading(pm::AbstractNCBFModelEdisgo, n::Int)
Non-convex-model version of the maximum-line-loading constraint
(p² + q²)/s_nom² ≤ ll (identical formulation to the SOC method) — Eq. (3.40).
constraint_power_balance
function constraint_power_balance(pm::AbstractBFModelEdisgo, n::Int, i, bus_gens, bus_gens_nd, bus_gens_slack, bus_loads, bus_arcs_to, bus_arcs_from, bus_lines_to, bus_storage, bus_pg, bus_qg, bus_pg_nd, bus_qg_nd, bus_pd, bus_qd, branch_r, branch_x, bus_dsm, bus_hps, bus_cps, bus_storage_pf, bus_dsm_pf, bus_hps_pf, bus_cps_pf, bus_gen_nd_pf, bus_gen_d_pf, bus_loads_pf, branch_strg_pf)
Nodal active- and reactive-power balance (Kirchhoff’s current law) at bus i in
network n for the radial branch-flow model — Eq. (3.3)/(3.4) of the eDisGo OPF
formulation.
Equates the power flowing into the bus on incoming branches to the power leaving
on outgoing branches plus the net injection of every component connected to the
bus: conventional and non-dispatchable generators, slack generator, loads, battery
storage, DSM, heat pumps and charging points, plus the ohmic branch losses
(ccm·r for active, ccm·x for reactive power). For opf_version 2 and 4 the
balance additionally includes the load-shedding / curtailment slack variables
(generation curtailment pgc, dispatchable-generation slack pgens, load slack
pds, charging-point slack pcps, heat-pump slack phps). Reactive injections
of the flexibilities are derived from their active power via the power factor
(tan(acos(pf))).
This low-level method receives the pre-collected per-bus component maps from
constraint_power_balance_bf.
Objective functions
Source: edisgo/opf/eDisGo_OPF.jl/src/core/objective.jl
objective_min_losses
function objective_min_losses(pm::AbstractBFModelEdisgo)
Objective: minimise total ohmic line losses, summed over all time steps, as
Σ ccm[b]·r[b] over the non-storage branches. (Defined as an alternative
objective; the multi-network build uses objective_min_line_loading_max for
opf_version 1.)
objective_min_losses_slacks
function objective_min_losses_slacks(pm::AbstractBFModelEdisgo)
Objective for opf_version 2 — Eq. (3.2 iii) of the eDisGo OPF formulation:
minimise a weighted sum of line losses and the grid-restriction slacks. Combines
ohmic losses (Σ ccm·r) with penalties on non-dispatchable curtailment (pgc),
dispatchable-generation curtailment (pgens), load shedding (pds),
charging-point shedding (pcps) and heat-pump shedding (phps), weighted by
factor_slacks, plus a large penalty on the heat-storage / heat-pump operation
slacks (phss, phps2).
objective_min_line_loading_max
function objective_min_line_loading_max(pm::AbstractBFModelEdisgo)
Objective for opf_version 1 — Eq. (3.2 ii) of the eDisGo OPF formulation:
minimise a weighted sum of line losses (Σ ccm·r) and the maximum line loading
ll (weighted by factor_ll, scaled by branch cost × length) over the
non-storage branches.
objective_min_losses_slacks_OG
function objective_min_losses_slacks_OG(pm::AbstractBFModelEdisgo)
Objective for opf_version 4 (with overlying grid): like
objective_min_losses_slacks, but additionally penalises the overlying-grid (HV)
requirement slacks phvs (with a reduced weight for DSM requirements). The HV
penalty factor is scaled from the branch resistances.
objective_min_line_loading_max_OG
function objective_min_line_loading_max_OG(pm::AbstractBFModelEdisgo)
Objective for opf_version 3 (with overlying grid): like
objective_min_line_loading_max (losses + maximum line loading), but additionally
penalises the overlying-grid (HV) requirement slacks phvs (reduced weight for
DSM).
Data preparation
Source: edisgo/opf/eDisGo_OPF.jl/src/core/data.jl
set_ac_bf_start_values!
function set_ac_bf_start_values!(network::Dict{String,<:Any})
Seed warm-start values on a (single-network) data dict: copy each flexibility’s
optimised power/energy results into the corresponding *_start fields, so a
subsequent non-convex (Ipopt) solve can be warm-started from a previous solution.
Used in the SOC → NC warm_start workflow.
correct_bus_types!
function correct_bus_types!(data::Dict{String,<:Any})
checks bus types are suitable for a power flow study, if not, fixes them.
the primary checks are that all type 2 buses (i.e., PV) have a connected and active generator and there is a single type 3 bus (i.e., slack bus) with an active connected generator.
assumes that the network is a single connected component
_correct_bus_types!
function _correct_bus_types!(pm_data::Dict{String,<:Any})
Internal worker for correct_bus_types!, operating on a single (non-multinetwork)
PowerModels data dict.
Demotes PV buses (type 2) without an active generator to PQ (type 1), validates
the slack bus (type 3), and — if no slack bus is found — promotes the bus of the
largest generator to slack. See correct_bus_types! for the public entry point.
Solution processing
Source: edisgo/opf/eDisGo_OPF.jl/src/core/solution.jl
sol_component_value_radial
function sol_component_value_radial(aim::AbstractPowerModel, n::Int, comp_name::Symbol, field_name_to::Symbol, comp_ids_to, variables)
Solution processor: write a per-branch variable indexed by the directed arc
(l, i, j) (e.g. the branch flows) back into the PowerModels solution dict under
field_name_to, for the radial branch-flow model. The arc-indexed counterpart of
PowerModels’ sol_component_value.
check_SOC_equality
function check_SOC_equality(result, data_edisgo)
Check whether the second-order-cone relaxation is tight in a solved SOC result.
For every non-storage branch and time step it compares pf² + qf² against
ccm · w (the SOC inequality); a gap below -1e-1 means the cone is not tight
there. Returns (soc_tight, soc_eq_dict), where soc_tight::Bool and
soc_eq_dict maps each time step to its offending branches. Used to decide whether
a warm_start AC polishing step is needed (see SOCBFPowerModelEdisgo).
I/O — network validation
Source: edisgo/opf/eDisGo_OPF.jl/src/io/common.jl
correct_network_data!
function correct_network_data!(data::Dict{String,<:Any})
Validate and normalise the parsed PowerModels network data before the OPF is
built: runs the connectivity / status / limit checks, converts everything to
per-unit (make_per_unit!), corrects transformer / voltage-angle / thermal /
current limits and branch directions, checks storage / switch / voltage setpoints,
and simplifies the cost terms. Called by parse_json when validation is enabled.
I/O — JSON parsing
Source: edisgo/opf/eDisGo_OPF.jl/src/io/json.jl
parse_json
function parse_json(io::Union{IO,String}; kwargs...)::Dict{String,Any}
Parses json from iostream or string