mirror of
https://github.com/ANL-CEEESA/UnitCommitment.jl.git
synced 2025-12-06 16:28:51 -06:00
Fix all tests
This commit is contained in:
@@ -17,6 +17,7 @@ MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
|
|||||||
PackageCompiler = "9b87118b-4619-50d2-8e1e-99f35a4d4d9d"
|
PackageCompiler = "9b87118b-4619-50d2-8e1e-99f35a4d4d9d"
|
||||||
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
|
Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7"
|
||||||
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
|
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
|
||||||
|
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
|
||||||
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
|
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
|
||||||
|
|
||||||
[compat]
|
[compat]
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ end
|
|||||||
|
|
||||||
function _total_reserves(model, g)::Vector
|
function _total_reserves(model, g)::Vector
|
||||||
T = model[:instance].time
|
T = model[:instance].time
|
||||||
reserve = 0.0
|
reserve = [0.0 for _ in 1:T]
|
||||||
if !isempty(g.reserves)
|
if !isempty(g.reserves)
|
||||||
reserve += [
|
reserve += [
|
||||||
sum(model[:reserve][r.name, g.name, t] for r in g.reserves) for
|
sum(model[:reserve][r.name, g.name, t] for r in g.reserves) for
|
||||||
|
|||||||
@@ -18,15 +18,27 @@ function fix!(model::JuMP.Model, solution::AbstractDict)::Nothing
|
|||||||
is_on_value = round(solution["Is on"][g.name][t])
|
is_on_value = round(solution["Is on"][g.name][t])
|
||||||
prod_value =
|
prod_value =
|
||||||
round(solution["Production (MW)"][g.name][t], digits = 5)
|
round(solution["Production (MW)"][g.name][t], digits = 5)
|
||||||
reserve_value =
|
|
||||||
round(solution["Reserve (MW)"][g.name][t], digits = 5)
|
|
||||||
JuMP.fix(is_on[g.name, t], is_on_value, force = true)
|
JuMP.fix(is_on[g.name, t], is_on_value, force = true)
|
||||||
JuMP.fix(
|
JuMP.fix(
|
||||||
prod_above[g.name, t],
|
prod_above[g.name, t],
|
||||||
prod_value - is_on_value * g.min_power[t],
|
prod_value - is_on_value * g.min_power[t],
|
||||||
force = true,
|
force = true,
|
||||||
)
|
)
|
||||||
JuMP.fix(reserve[g.name, t], reserve_value, force = true)
|
end
|
||||||
|
end
|
||||||
|
for r in instance.reserves
|
||||||
|
for g in r.units
|
||||||
|
for t in 1:T
|
||||||
|
reserve_value = round(
|
||||||
|
solution["Reserve (MW)"][r.name][g.name][t],
|
||||||
|
digits = 5,
|
||||||
|
)
|
||||||
|
JuMP.fix(
|
||||||
|
reserve[r.name, g.name, t],
|
||||||
|
reserve_value,
|
||||||
|
force = true,
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -24,13 +24,14 @@ function slice(
|
|||||||
modified = deepcopy(instance)
|
modified = deepcopy(instance)
|
||||||
modified.time = length(range)
|
modified.time = length(range)
|
||||||
modified.power_balance_penalty = modified.power_balance_penalty[range]
|
modified.power_balance_penalty = modified.power_balance_penalty[range]
|
||||||
modified.reserves.spinning = modified.reserves.spinning[range]
|
for r in modified.reserves
|
||||||
|
r.amount = r.amount[range]
|
||||||
|
end
|
||||||
for u in modified.units
|
for u in modified.units
|
||||||
u.max_power = u.max_power[range]
|
u.max_power = u.max_power[range]
|
||||||
u.min_power = u.min_power[range]
|
u.min_power = u.min_power[range]
|
||||||
u.must_run = u.must_run[range]
|
u.must_run = u.must_run[range]
|
||||||
u.min_power_cost = u.min_power_cost[range]
|
u.min_power_cost = u.min_power_cost[range]
|
||||||
u.provides_spinning_reserves = u.provides_spinning_reserves[range]
|
|
||||||
for s in u.cost_segments
|
for s in u.cost_segments
|
||||||
s.mw = s.mw[range]
|
s.mw = s.mw[range]
|
||||||
s.cost = s.cost[range]
|
s.cost = s.cost[range]
|
||||||
|
|||||||
@@ -40,15 +40,15 @@ function validate(
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function _validate_units(instance, solution; tol = 0.01)
|
function _validate_units(instance::UnitCommitmentInstance, solution; tol = 0.01)
|
||||||
err_count = 0
|
err_count = 0
|
||||||
|
|
||||||
for unit in instance.units
|
for unit in instance.units
|
||||||
production = solution["Production (MW)"][unit.name]
|
production = solution["Production (MW)"][unit.name]
|
||||||
reserve = solution["Reserve (MW)"][unit.name]
|
reserve = [0.0 for _ in 1:instance.time]
|
||||||
if !isempty(unit.reserves)
|
if !isempty(unit.reserves)
|
||||||
reserve += sum(
|
reserve += sum(
|
||||||
solution["Reserve 2 (MW)"][r.name][unit.name] for
|
solution["Reserve (MW)"][r.name][unit.name] for
|
||||||
r in unit.reserves
|
r in unit.reserves
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
@@ -105,14 +105,17 @@ function _validate_units(instance, solution; tol = 0.01)
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Verify reserve eligibility
|
# Verify reserve eligibility
|
||||||
if !unit.provides_spinning_reserves[t] && reserve[t] > tol
|
for r in instance.reserves
|
||||||
|
if unit ∉ r.units &&
|
||||||
|
(unit in keys(solution["Reserve (MW)"][r.name]))
|
||||||
@error @sprintf(
|
@error @sprintf(
|
||||||
"Unit %s is not eligible to provide spinning reserves at time %d",
|
"Unit %s is not eligible to provide reserve %s",
|
||||||
unit.name,
|
unit.name,
|
||||||
t
|
r.name,
|
||||||
)
|
)
|
||||||
err_count += 1
|
err_count += 1
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# If unit is on, must produce at least its minimum power
|
# If unit is on, must produce at least its minimum power
|
||||||
if is_on[t] && (production[t] < unit.min_power[t] - tol)
|
if is_on[t] && (production[t] < unit.min_power[t] - tol)
|
||||||
|
|||||||
BIN
test/fixtures/case118-initcond.json.gz
vendored
BIN
test/fixtures/case118-initcond.json.gz
vendored
Binary file not shown.
@@ -12,7 +12,6 @@ using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON, GZip
|
|||||||
@test length(instance.units) == 6
|
@test length(instance.units) == 6
|
||||||
@test length(instance.contingencies) == 19
|
@test length(instance.contingencies) == 19
|
||||||
@test length(instance.price_sensitive_loads) == 1
|
@test length(instance.price_sensitive_loads) == 1
|
||||||
@test length(instance.reserves2) == 1
|
|
||||||
@test instance.time == 4
|
@test instance.time == 4
|
||||||
|
|
||||||
@test instance.lines[5].name == "l5"
|
@test instance.lines[5].name == "l5"
|
||||||
@@ -38,9 +37,9 @@ using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON, GZip
|
|||||||
@test instance.buses[9].load == [35.36638, 33.25495, 31.67138, 31.14353]
|
@test instance.buses[9].load == [35.36638, 33.25495, 31.67138, 31.14353]
|
||||||
@test instance.buses_by_name["b9"].name == "b9"
|
@test instance.buses_by_name["b9"].name == "b9"
|
||||||
|
|
||||||
@test instance.reserves2[1].name == "r1"
|
@test instance.reserves[1].name == "r1"
|
||||||
@test instance.reserves2[1].type == "spinning"
|
@test instance.reserves[1].type == "spinning"
|
||||||
@test instance.reserves2[1].amount == [100.0, 100.0, 100.0, 100.0]
|
@test instance.reserves[1].amount == [100.0, 100.0, 100.0, 100.0]
|
||||||
@test instance.reserves_by_name["r1"].name == "r1"
|
@test instance.reserves_by_name["r1"].name == "r1"
|
||||||
|
|
||||||
unit = instance.units[1]
|
unit = instance.units[1]
|
||||||
@@ -54,7 +53,6 @@ using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON, GZip
|
|||||||
@test unit.min_power_cost == [1400.0 for t in 1:4]
|
@test unit.min_power_cost == [1400.0 for t in 1:4]
|
||||||
@test unit.min_uptime == 1
|
@test unit.min_uptime == 1
|
||||||
@test unit.min_downtime == 1
|
@test unit.min_downtime == 1
|
||||||
@test unit.provides_spinning_reserves == [true for t in 1:4]
|
|
||||||
for t in 1:1
|
for t in 1:1
|
||||||
@test unit.cost_segments[1].mw[t] == 10.0
|
@test unit.cost_segments[1].mw[t] == 10.0
|
||||||
@test unit.cost_segments[2].mw[t] == 20.0
|
@test unit.cost_segments[2].mw[t] == 20.0
|
||||||
@@ -89,7 +87,6 @@ using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON, GZip
|
|||||||
@test unit.min_power_cost == [0.0 for t in 1:4]
|
@test unit.min_power_cost == [0.0 for t in 1:4]
|
||||||
@test unit.min_uptime == 1
|
@test unit.min_uptime == 1
|
||||||
@test unit.min_downtime == 1
|
@test unit.min_downtime == 1
|
||||||
@test unit.provides_spinning_reserves == [true for t in 1:4]
|
|
||||||
for t in 1:4
|
for t in 1:4
|
||||||
@test unit.cost_segments[1].mw[t] ≈ 33
|
@test unit.cost_segments[1].mw[t] ≈ 33
|
||||||
@test unit.cost_segments[2].mw[t] ≈ 33
|
@test unit.cost_segments[2].mw[t] ≈ 33
|
||||||
@@ -99,8 +96,7 @@ using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON, GZip
|
|||||||
@test unit.cost_segments[3].cost[t] ≈ 44.77853
|
@test unit.cost_segments[3].cost[t] ≈ 44.77853
|
||||||
end
|
end
|
||||||
@test length(unit.reserves) == 1
|
@test length(unit.reserves) == 1
|
||||||
|
@test unit.reserves[1].name == "r1"
|
||||||
@test instance.reserves.spinning == zeros(4)
|
|
||||||
|
|
||||||
@test instance.contingencies[1].lines == [instance.lines[1]]
|
@test instance.contingencies[1].lines == [instance.lines[1]]
|
||||||
@test instance.contingencies[1].units == []
|
@test instance.contingencies[1].units == []
|
||||||
|
|||||||
@@ -11,13 +11,12 @@ using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON, GZip
|
|||||||
# Should update all time-dependent fields
|
# Should update all time-dependent fields
|
||||||
@test modified.time == 2
|
@test modified.time == 2
|
||||||
@test length(modified.power_balance_penalty) == 2
|
@test length(modified.power_balance_penalty) == 2
|
||||||
@test length(modified.reserves.spinning) == 2
|
@test length(modified.reserves_by_name["r1"].amount) == 2
|
||||||
for u in modified.units
|
for u in modified.units
|
||||||
@test length(u.max_power) == 2
|
@test length(u.max_power) == 2
|
||||||
@test length(u.min_power) == 2
|
@test length(u.min_power) == 2
|
||||||
@test length(u.must_run) == 2
|
@test length(u.must_run) == 2
|
||||||
@test length(u.min_power_cost) == 2
|
@test length(u.min_power_cost) == 2
|
||||||
@test length(u.provides_spinning_reserves) == 2
|
|
||||||
for s in u.cost_segments
|
for s in u.cost_segments
|
||||||
@test length(s.mw) == 2
|
@test length(s.mw) == 2
|
||||||
@test length(s.cost) == 2
|
@test length(s.cost) == 2
|
||||||
|
|||||||
Reference in New Issue
Block a user