Skip to content

Commit

Permalink
Add multiperiod threshold ops problem (#34)
Browse files Browse the repository at this point in the history
  • Loading branch information
noahrhodes authored Apr 25, 2024
1 parent fc7cbba commit c3d4944
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 1 deletion.
25 changes: 24 additions & 1 deletion src/core/constraint.jl
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ function constraint_voltage_magnitude_sqr_on_off(pm::_PM.AbstractPowerModel, n::
end

function constraint_load_served(pm::_PM.AbstractPowerModel)
threshold= _PM.ref(pm, :threshold)
nw1 = first(_PM.nw_ids(pm))
threshold= _PM.ref(pm, nw1, :threshold)
total_demand = sum(sum(load["pd"] for (id,load) in _PM.ref(pm, nwid, :load)) for nwid in _PM.nw_ids(pm))
z_demand = Dict(nwid => _PM.var(pm, nwid, :z_demand) for nwid in _PM.nw_ids(pm))

Expand All @@ -118,3 +119,25 @@ function constraint_load_served(pm::_PM.AbstractPowerModel)
) >= threshold*total_demand
)
end

function consistent_shutoff_variables(pm::_PM.AbstractPowerModel)
nw1 = first(_PM.nw_ids(pm))
for nwid in _PM.nw_ids(pm)
for i in _PM.ids(pm, nwid, :branch)
z_branch_1 = _PM.var(pm, nw1, :z_branch, i)
z_branch_nwid = _PM.var(pm, nwid, :z_branch, i)
JuMP.@constraint(pm.model, z_branch_1 == z_branch_nwid)
end
for i in _PM.ids(pm, nwid, :gen)
z_gen_1 = _PM.var(pm, nw1, :z_gen, i)
z_gen_nwid = _PM.var(pm, nwid, :z_gen, i)
JuMP.@constraint(pm.model, z_gen_1 == z_gen_nwid)
end
for i in _PM.ids(pm, nwid, :bus)
z_bus_1 = _PM.var(pm, nw1, :z_bus, i)
z_bus_nwid = _PM.var(pm, nwid, :z_bus, i)
JuMP.@constraint(pm.model, z_bus_1 == z_bus_nwid)
end
end
end

126 changes: 126 additions & 0 deletions src/prob/test.jl
Original file line number Diff line number Diff line change
Expand Up @@ -794,4 +794,130 @@ function _build_redispatch(pm::_PM.AbstractPowerModel)
)
end

# MOPS Threshold (single shutoff variable across periods)
""
function _run_strg_mops_threshold(file, model_constructor::Type, optimizer; kwargs...)
return _PM.solve_model(file, model_constructor, optimizer, _build_mn_strg_ops_threshold;
multinetwork=true, ref_extensions=[_PM.ref_add_on_off_va_bounds!], kwargs...)
end


function _build_mn_strg_ops_threshold(pm::_PM.AbstractPowerModel)
for (n, network) in _PM.nws(pm)

variable_bus_active_indicator(pm, nw=n)
variable_bus_voltage_on_off(pm, nw=n)

_PM.variable_gen_indicator(pm, nw=n)
_PM.variable_gen_power_on_off(pm, nw=n)

_PM.variable_storage_indicator(pm, nw=n)
_PM.variable_storage_power_mi_on_off(pm, nw=n)

_PM.variable_branch_indicator(pm, nw=n)
_PM.variable_branch_power(pm, nw=n)

_PM.variable_load_power_factor(pm, nw=n, relax=true)
_PM.variable_shunt_admittance_factor(pm, nw=n, relax=true)

_PM.constraint_model_voltage_on_off(pm, nw=n)
for i in _PM.ids(pm, :ref_buses, nw=n)
_PM.constraint_theta_ref(pm, i, nw=n)
end

for i in _PM.ids(pm, :gen, nw=n)
constraint_generation_active(pm, i, nw=n)
end

for i in _PM.ids(pm, :bus, nw=n)
constraint_bus_voltage_on_off(pm, i, nw=n)
_PMR.constraint_power_balance_shed(pm, i, nw=n)
end

for i in _PM.ids(pm, :storage, nw=n)
constraint_storage_active(pm, i, nw=n)
_PM.constraint_storage_state(pm, i, nw=n)
_PM.constraint_storage_complementarity_mi(pm, i, nw=n)
_PM.constraint_storage_on_off(pm,i, nw=n)
_PM.constraint_storage_losses(pm, i, nw=n)
_PM.constraint_storage_thermal_limit(pm, i, nw=n)
end

for i in _PM.ids(pm, :branch, nw=n)
constraint_branch_active(pm, i, nw=n)
_PM.constraint_ohms_yt_from_on_off(pm, i, nw=n)
_PM.constraint_ohms_yt_to_on_off(pm, i, nw=n)

_PM.constraint_voltage_angle_difference_on_off(pm, i, nw=n)

_PM.constraint_thermal_limit_from_on_off(pm, i, nw=n)
_PM.constraint_thermal_limit_to_on_off(pm, i, nw=n)
end

for i in _PM.ids(pm, :load, nw=n)
constraint_load_active(pm, i, nw=n)
end
end

network_ids = sort(collect(_PM.nw_ids(pm)))

n_1 = network_ids[1]
for i in _PM.ids(pm, :storage, nw=n_1)
_PM.constraint_storage_state(pm, i, nw=n_1)
end

for n_2 in network_ids[2:end]
for i in _PM.ids(pm, :storage, nw=n_2)
_PM.constraint_storage_state(pm, i, n_1, n_2)
end
n_1 = n_2
end

constraint_load_served(pm) # threshold for load served
consistent_shutoff_variables(pm)

# Add Objective Function
# ----------------------
# Maximize power delivery while minimizing wildfire risk
n_1 = network_ids[1]
if haskey(_PM.ref(pm, n_1), :risk_weight)
alpha = _PM.ref(pm, n_1, :risk_weight)
else
Memento.warn(_PM._LOGGER, "network data should specify risk_weight, using 0.5 as a default")
alpha = 0.5
end

for comp_type in [:gen, :load, :bus, :branch]
for nwid in _PM.nw_ids(pm)
for (id,comp) in _PM.ref(pm, nwid, comp_type)
if ~haskey(comp, "power_risk")
Memento.warn(_PM._LOGGER, "$(comp_type) $(id) does not have a power_risk value, using 0.0 as a default")
comp["power_risk"] = 0.0
end
end
end
end

load_weight = Dict(nwid =>
Dict(i => get(load, "weight", 1.0) for (i,load) in _PM.ref(pm, nwid, :load))
for nwid in _PM.nw_ids(pm))

z_demand = Dict(nwid => _PM.var(pm, nwid, :z_demand) for nwid in _PM.nw_ids(pm))
z_storage = Dict(nwid => _PM.var(pm, nwid, :z_storage) for nwid in _PM.nw_ids(pm))
z_branch = Dict(nwid => _PM.var(pm, nwid, :z_branch) for nwid in _PM.nw_ids(pm))
z_bus = Dict(nwid => _PM.var(pm, nwid, :z_bus) for nwid in _PM.nw_ids(pm))
z_gen = Dict(nwid => _PM.var(pm, nwid, :z_gen) for nwid in _PM.nw_ids(pm))

JuMP.@objective(pm.model, Min,
sum(
sum(z_branch[nwid][i]*branch["power_risk"] for (i,branch) in _PM.ref(pm, nwid, :branch))+
sum(z_bus[nwid][i]*bus["power_risk"] for (i,bus) in _PM.ref(pm, nwid, :bus))+
sum(z_gen[nwid][i]*gen["power_risk"] for (i,gen) in _PM.ref(pm, nwid, :gen))+
sum(z_demand[nwid][i]*load["power_risk"] for (i,load) in _PM.ref(pm, nwid, :load))+
sum(z_storage[nwid][i]*storage["power_risk"] for (i,storage) in _PM.ref(pm, nwid, :storage))
for nwid in _PM.nw_ids(pm)
)
)
end


0 comments on commit c3d4944

Please sign in to comment.