Reformat source code

feature/reserves
Alinson S. Xavier 3 years ago
parent dc693896a3
commit fd25580967

@ -30,7 +30,9 @@ function _add_ramp_eqs!(
end end
for r in g.reserves for r in g.reserves
if r.type !== "flexiramp" if r.type !== "flexiramp"
error("This formulation only supports flexiramp reserves, not $(r.type)") error(
"This formulation only supports flexiramp reserves, not $(r.type)",
)
end end
rn = r.name rn = r.name
for t in 1:model[:instance].time for t in 1:model[:instance].time
@ -110,7 +112,8 @@ function _add_ramp_eqs!(
) # Eq. (24) in Wang & Hobbs (2016) ) # Eq. (24) in Wang & Hobbs (2016)
@constraint( @constraint(
model, model,
-RD * is_on[gn, t+1] - SD * (is_on[gn, t] - is_on[gn, t+1]) - -RD * is_on[gn, t+1] -
SD * (is_on[gn, t] - is_on[gn, t+1]) -
maxp[t] * (1 - is_on[gn, t]) <= upflexiramp[rn, gn, t] maxp[t] * (1 - is_on[gn, t]) <= upflexiramp[rn, gn, t]
) # first inequality of Eq. (26) in Wang & Hobbs (2016) ) # first inequality of Eq. (26) in Wang & Hobbs (2016)
@constraint( @constraint(
@ -137,8 +140,14 @@ function _add_ramp_eqs!(
-maxp[t] * is_on[gn, t] + minp[t] * is_on[gn, t+1] <= -maxp[t] * is_on[gn, t] + minp[t] * is_on[gn, t+1] <=
upflexiramp[rn, gn, t] upflexiramp[rn, gn, t]
) # first inequality of Eq. (28) in Wang & Hobbs (2016) ) # first inequality of Eq. (28) in Wang & Hobbs (2016)
@constraint(model, upflexiramp[rn, gn, t] <= maxp[t] * is_on[gn, t+1]) # second inequality of Eq. (28) in Wang & Hobbs (2016) @constraint(
@constraint(model, -maxp[t] * is_on[gn, t+1] <= dwflexiramp[rn, gn, t]) # first inequality of Eq. (29) in Wang & Hobbs (2016) model,
upflexiramp[rn, gn, t] <= maxp[t] * is_on[gn, t+1]
) # second inequality of Eq. (28) in Wang & Hobbs (2016)
@constraint(
model,
-maxp[t] * is_on[gn, t+1] <= dwflexiramp[rn, gn, t]
) # first inequality of Eq. (29) in Wang & Hobbs (2016)
@constraint( @constraint(
model, model,
dwflexiramp[rn, gn, t] <= dwflexiramp[rn, gn, t] <=

@ -72,14 +72,12 @@ function _add_flexiramp_reserve_eqs!(model::JuMP.Model)::Nothing
# Eq. (17) in Wang & Hobbs (2016) # Eq. (17) in Wang & Hobbs (2016)
eq_min_upflexiramp[r.name, t] = @constraint( eq_min_upflexiramp[r.name, t] = @constraint(
model, model,
sum(model[:upflexiramp][r.name, g.name, t] for g in r.units) + sum(model[:upflexiramp][r.name, g.name, t] for g in r.units) + model[:upflexiramp_shortfall][r.name, t] >= r.amount[t]
model[:upflexiramp_shortfall][r.name, t] >= r.amount[t]
) )
# Eq. (18) in Wang & Hobbs (2016) # Eq. (18) in Wang & Hobbs (2016)
eq_min_dwflexiramp[r.name, t] = @constraint( eq_min_dwflexiramp[r.name, t] = @constraint(
model, model,
sum(model[:dwflexiramp][r.name, g.name, t] for g in r.units) + sum(model[:dwflexiramp][r.name, g.name, t] for g in r.units) + model[:dwflexiramp_shortfall][r.name, t] >= r.amount[t]
model[:dwflexiramp_shortfall][r.name, t] >= r.amount[t]
) )
# Account for flexiramp shortfall contribution to objective # Account for flexiramp shortfall contribution to objective

@ -75,8 +75,10 @@ function _add_flexiramp_reserve_vars!(model::JuMP.Model, g::Unit)::Nothing
upflexiramp[r.name, g.name, t] = @variable(model) # up-flexiramp, ur_{it} in Wang & Hobbs (2016) upflexiramp[r.name, g.name, t] = @variable(model) # up-flexiramp, ur_{it} in Wang & Hobbs (2016)
dwflexiramp[r.name, g.name, t] = @variable(model) # down-flexiramp, dr_{it} in Wang & Hobbs (2016) dwflexiramp[r.name, g.name, t] = @variable(model) # down-flexiramp, dr_{it} in Wang & Hobbs (2016)
if (r.name, t) keys(upflexiramp_shortfall) if (r.name, t) keys(upflexiramp_shortfall)
upflexiramp_shortfall[r.name, t] = @variable(model, lower_bound = 0) upflexiramp_shortfall[r.name, t] =
dwflexiramp_shortfall[r.name, t] = @variable(model, lower_bound = 0) @variable(model, lower_bound = 0)
dwflexiramp_shortfall[r.name, t] =
@variable(model, lower_bound = 0)
if r.shortfall_penalty < 0 if r.shortfall_penalty < 0
set_upper_bound(upflexiramp_shortfall[r.name, t], 0.0) set_upper_bound(upflexiramp_shortfall[r.name, t], 0.0)
set_upper_bound(dwflexiramp_shortfall[r.name, t], 0.0) set_upper_bound(dwflexiramp_shortfall[r.name, t], 0.0)
@ -204,14 +206,16 @@ function _add_min_uptime_downtime_eqs!(model::JuMP.Model, g::Unit)::Nothing
eq_min_uptime[g.name, 0] = @constraint( eq_min_uptime[g.name, 0] = @constraint(
model, model,
sum( sum(
switch_off[g.name, i] for i in 1:(g.min_uptime-g.initial_status) if i <= T switch_off[g.name, i] for
i in 1:(g.min_uptime-g.initial_status) if i <= T
) == 0 ) == 0
) )
else else
eq_min_downtime[g.name, 0] = @constraint( eq_min_downtime[g.name, 0] = @constraint(
model, model,
sum( sum(
switch_on[g.name, i] for i in 1:(g.min_downtime+g.initial_status) if i <= T switch_on[g.name, i] for
i in 1:(g.min_downtime+g.initial_status) if i <= T
) == 0 ) == 0
) )
end end

@ -15,7 +15,8 @@ function solution(model::JuMP.Model)::OrderedDict
value(model[:is_on][g.name, t]) * g.min_power_cost[t] + sum( value(model[:is_on][g.name, t]) * g.min_power_cost[t] + sum(
Float64[ Float64[
value(model[:segprod][g.name, t, k]) * value(model[:segprod][g.name, t, k]) *
g.cost_segments[k].cost[t] for k in 1:length(g.cost_segments) g.cost_segments[k].cost[t] for
k in 1:length(g.cost_segments)
], ],
) for t in 1:T ) for t in 1:T
] ]
@ -24,7 +25,8 @@ function solution(model::JuMP.Model)::OrderedDict
return [ return [
value(model[:is_on][g.name, t]) * g.min_power[t] + sum( value(model[:is_on][g.name, t]) * g.min_power[t] + sum(
Float64[ Float64[
value(model[:segprod][g.name, t, k]) for k in 1:length(g.cost_segments) value(model[:segprod][g.name, t, k]) for
k in 1:length(g.cost_segments)
], ],
) for t in 1:T ) for t in 1:T
] ]
@ -61,41 +63,43 @@ function solution(model::JuMP.Model)::OrderedDict
sol["Spinning reserve (MW)"] = OrderedDict( sol["Spinning reserve (MW)"] = OrderedDict(
r.name => OrderedDict( r.name => OrderedDict(
g.name => [ g.name => [
value(model[:reserve][r.name, g.name, t]) for t in 1:instance.time value(model[:reserve][r.name, g.name, t]) for
t in 1:instance.time
] for g in r.units ] for g in r.units
) for r in instance.reserves if r.type == "spinning" ) for r in instance.reserves if r.type == "spinning"
) )
sol["Spinning reserve shortfall (MW)"] = OrderedDict( sol["Spinning reserve shortfall (MW)"] = OrderedDict(
r.name => [ r.name => [
value(model[:reserve_shortfall][r.name, t]) for t in 1:instance.time value(model[:reserve_shortfall][r.name, t]) for
t in 1:instance.time
] for r in instance.reserves if r.type == "spinning" ] for r in instance.reserves if r.type == "spinning"
) )
sol["Up-flexiramp (MW)"] = OrderedDict( sol["Up-flexiramp (MW)"] = OrderedDict(
r.name => OrderedDict( r.name => OrderedDict(
g.name => [ g.name => [
value(model[:upflexiramp][r.name, g.name, t]) value(model[:upflexiramp][r.name, g.name, t]) for
for t in 1:instance.time t in 1:instance.time
] for g in r.units ] for g in r.units
) for r in instance.reserves if r.type == "flexiramp" ) for r in instance.reserves if r.type == "flexiramp"
) )
sol["Up-flexiramp shortfall (MW)"] = OrderedDict( sol["Up-flexiramp shortfall (MW)"] = OrderedDict(
r.name => [ r.name => [
value(model[:upflexiramp_shortfall][r.name, t]) value(model[:upflexiramp_shortfall][r.name, t]) for
for t in 1:instance.time t in 1:instance.time
] for r in instance.reserves if r.type == "flexiramp" ] for r in instance.reserves if r.type == "flexiramp"
) )
sol["Down-flexiramp (MW)"] = OrderedDict( sol["Down-flexiramp (MW)"] = OrderedDict(
r.name => OrderedDict( r.name => OrderedDict(
g.name => [ g.name => [
value(model[:dwflexiramp][r.name, g.name, t]) value(model[:dwflexiramp][r.name, g.name, t]) for
for t in 1:instance.time t in 1:instance.time
] for g in r.units ] for g in r.units
) for r in instance.reserves if r.type == "flexiramp" ) for r in instance.reserves if r.type == "flexiramp"
) )
sol["Down-flexiramp shortfall (MW)"] = OrderedDict( sol["Down-flexiramp shortfall (MW)"] = OrderedDict(
r.name => [ r.name => [
value(model[:upflexiramp_shortfall][r.name, t]) value(model[:upflexiramp_shortfall][r.name, t]) for
for t in 1:instance.time t in 1:instance.time
] for r in instance.reserves if r.type == "flexiramp" ] for r in instance.reserves if r.type == "flexiramp"
) )
return sol return sol

@ -49,8 +49,8 @@ function _validate_units(instance::UnitCommitmentInstance, solution; tol = 0.01)
spinning_reserves = [r for r in unit.reserves if r.type == "spinning"] spinning_reserves = [r for r in unit.reserves if r.type == "spinning"]
if !isempty(spinning_reserves) if !isempty(spinning_reserves)
reserve += sum( reserve += sum(
solution["Spinning reserve (MW)"][r.name][unit.name] solution["Spinning reserve (MW)"][r.name][unit.name] for
for r in spinning_reserves r in spinning_reserves
) )
end end
actual_production_cost = solution["Production cost (\$)"][unit.name] actual_production_cost = solution["Production cost (\$)"][unit.name]
@ -308,14 +308,16 @@ function _validate_reserve_and_demand(instance, solution, tol = 0.01)
ps_load = 0 ps_load = 0
if length(instance.price_sensitive_loads) > 0 if length(instance.price_sensitive_loads) > 0
ps_load = sum( ps_load = sum(
solution["Price-sensitive loads (MW)"][ps.name][t] for ps in instance.price_sensitive_loads solution["Price-sensitive loads (MW)"][ps.name][t] for
ps in instance.price_sensitive_loads
) )
end end
production = production =
sum(solution["Production (MW)"][g.name][t] for g in instance.units) sum(solution["Production (MW)"][g.name][t] for g in instance.units)
if "Load curtail (MW)" in keys(solution) if "Load curtail (MW)" in keys(solution)
load_curtail = sum( load_curtail = sum(
solution["Load curtail (MW)"][b.name][t] for b in instance.buses solution["Load curtail (MW)"][b.name][t] for
b in instance.buses
) )
end end
balance = fixed_load - load_curtail - production + ps_load balance = fixed_load - load_curtail - production + ps_load
@ -337,9 +339,11 @@ function _validate_reserve_and_demand(instance, solution, tol = 0.01)
for r in instance.reserves for r in instance.reserves
if r.type == "spinning" if r.type == "spinning"
provided = sum( provided = sum(
solution["Spinning reserve (MW)"][r.name][g.name][t] for g in r.units solution["Spinning reserve (MW)"][r.name][g.name][t] for
g in r.units
) )
shortfall = solution["Spinning reserve shortfall (MW)"][r.name][t] shortfall =
solution["Spinning reserve shortfall (MW)"][r.name][t]
required = r.amount[t] required = r.amount[t]
if provided + shortfall < required - tol if provided + shortfall < required - tol
@ -354,7 +358,8 @@ function _validate_reserve_and_demand(instance, solution, tol = 0.01)
end end
elseif r.type == "flexiramp" elseif r.type == "flexiramp"
upflexiramp = sum( upflexiramp = sum(
solution["Up-flexiramp (MW)"][r.name][g.name][t] for g in r.units solution["Up-flexiramp (MW)"][r.name][g.name][t] for
g in r.units
) )
upflexiramp_shortfall = upflexiramp_shortfall =
solution["Up-flexiramp shortfall (MW)"][r.name][t] solution["Up-flexiramp shortfall (MW)"][r.name][t]
@ -371,9 +376,11 @@ function _validate_reserve_and_demand(instance, solution, tol = 0.01)
end end
dwflexiramp = sum( dwflexiramp = sum(
solution["Down-flexiramp (MW)"][r.name][g.name][t] for g in r.units solution["Down-flexiramp (MW)"][r.name][g.name][t] for
g in r.units
) )
dwflexiramp_shortfall = solution["Down-flexiramp shortfall (MW)"][r.name][t] dwflexiramp_shortfall =
solution["Down-flexiramp shortfall (MW)"][r.name][t]
if dwflexiramp + dwflexiramp_shortfall < r.amount[t] - tol if dwflexiramp + dwflexiramp_shortfall < r.amount[t] - tol
@error @sprintf( @error @sprintf(

Loading…
Cancel
Save