|
|
@ -135,6 +135,7 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
|
|
|
|
lines = TransmissionLine[]
|
|
|
|
lines = TransmissionLine[]
|
|
|
|
loads = PriceSensitiveLoad[]
|
|
|
|
loads = PriceSensitiveLoad[]
|
|
|
|
reserves = Reserve[]
|
|
|
|
reserves = Reserve[]
|
|
|
|
|
|
|
|
profiled_units = ProfiledUnit[]
|
|
|
|
|
|
|
|
|
|
|
|
function scalar(x; default = nothing)
|
|
|
|
function scalar(x; default = nothing)
|
|
|
|
x !== nothing || return default
|
|
|
|
x !== nothing || return default
|
|
|
@ -182,6 +183,7 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
|
|
|
|
timeseries(dict["Load (MW)"]),
|
|
|
|
timeseries(dict["Load (MW)"]),
|
|
|
|
Unit[],
|
|
|
|
Unit[],
|
|
|
|
PriceSensitiveLoad[],
|
|
|
|
PriceSensitiveLoad[],
|
|
|
|
|
|
|
|
ProfiledUnit[],
|
|
|
|
)
|
|
|
|
)
|
|
|
|
name_to_bus[bus_name] = bus
|
|
|
|
name_to_bus[bus_name] = bus
|
|
|
|
push!(buses, bus)
|
|
|
|
push!(buses, bus)
|
|
|
@ -207,15 +209,25 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
|
|
|
|
|
|
|
|
|
|
|
|
# Read units
|
|
|
|
# Read units
|
|
|
|
for (unit_name, dict) in json["Generators"]
|
|
|
|
for (unit_name, dict) in json["Generators"]
|
|
|
|
|
|
|
|
# Read and validate unit type
|
|
|
|
|
|
|
|
unit_type = scalar(dict["Type"], default = nothing)
|
|
|
|
|
|
|
|
unit_type !== nothing || error("unit $unit_name has no type specified")
|
|
|
|
bus = name_to_bus[dict["Bus"]]
|
|
|
|
bus = name_to_bus[dict["Bus"]]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if lowercase(unit_type) === "thermal"
|
|
|
|
# Read production cost curve
|
|
|
|
# Read production cost curve
|
|
|
|
K = length(dict["Production cost curve (MW)"])
|
|
|
|
K = length(dict["Production cost curve (MW)"])
|
|
|
|
curve_mw = hcat(
|
|
|
|
curve_mw = hcat(
|
|
|
|
[timeseries(dict["Production cost curve (MW)"][k]) for k in 1:K]...,
|
|
|
|
[
|
|
|
|
|
|
|
|
timeseries(dict["Production cost curve (MW)"][k]) for
|
|
|
|
|
|
|
|
k in 1:K
|
|
|
|
|
|
|
|
]...,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
curve_cost = hcat(
|
|
|
|
curve_cost = hcat(
|
|
|
|
[timeseries(dict["Production cost curve (\$)"][k]) for k in 1:K]...,
|
|
|
|
[
|
|
|
|
|
|
|
|
timeseries(dict["Production cost curve (\$)"][k]) for
|
|
|
|
|
|
|
|
k in 1:K
|
|
|
|
|
|
|
|
]...,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
min_power = curve_mw[:, 1]
|
|
|
|
min_power = curve_mw[:, 1]
|
|
|
|
max_power = curve_mw[:, K]
|
|
|
|
max_power = curve_mw[:, K]
|
|
|
@ -250,14 +262,18 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
# Read and validate initial conditions
|
|
|
|
# Read and validate initial conditions
|
|
|
|
initial_power = scalar(dict["Initial power (MW)"], default = nothing)
|
|
|
|
initial_power =
|
|
|
|
initial_status = scalar(dict["Initial status (h)"], default = nothing)
|
|
|
|
scalar(dict["Initial power (MW)"], default = nothing)
|
|
|
|
|
|
|
|
initial_status =
|
|
|
|
|
|
|
|
scalar(dict["Initial status (h)"], default = nothing)
|
|
|
|
if initial_power === nothing
|
|
|
|
if initial_power === nothing
|
|
|
|
initial_status === nothing ||
|
|
|
|
initial_status === nothing || error(
|
|
|
|
error("unit $unit_name has initial status but no initial power")
|
|
|
|
"unit $unit_name has initial status but no initial power",
|
|
|
|
|
|
|
|
)
|
|
|
|
else
|
|
|
|
else
|
|
|
|
initial_status !== nothing ||
|
|
|
|
initial_status !== nothing || error(
|
|
|
|
error("unit $unit_name has initial power but no initial status")
|
|
|
|
"unit $unit_name has initial power but no initial status",
|
|
|
|
|
|
|
|
)
|
|
|
|
initial_status != 0 ||
|
|
|
|
initial_status != 0 ||
|
|
|
|
error("unit $unit_name has invalid initial status")
|
|
|
|
error("unit $unit_name has invalid initial status")
|
|
|
|
if initial_status < 0 && initial_power > 1e-3
|
|
|
|
if initial_status < 0 && initial_power > 1e-3
|
|
|
@ -274,8 +290,10 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
|
|
|
|
timeseries(dict["Must run?"], default = [false for t in 1:T]),
|
|
|
|
timeseries(dict["Must run?"], default = [false for t in 1:T]),
|
|
|
|
min_power_cost,
|
|
|
|
min_power_cost,
|
|
|
|
segments,
|
|
|
|
segments,
|
|
|
|
scalar(dict["Minimum uptime (h)"], default = 1) * time_multiplier,
|
|
|
|
scalar(dict["Minimum uptime (h)"], default = 1) *
|
|
|
|
scalar(dict["Minimum downtime (h)"], default = 1) * time_multiplier,
|
|
|
|
time_multiplier,
|
|
|
|
|
|
|
|
scalar(dict["Minimum downtime (h)"], default = 1) *
|
|
|
|
|
|
|
|
time_multiplier,
|
|
|
|
scalar(dict["Ramp up limit (MW)"], default = 1e6),
|
|
|
|
scalar(dict["Ramp up limit (MW)"], default = 1e6),
|
|
|
|
scalar(dict["Ramp down limit (MW)"], default = 1e6),
|
|
|
|
scalar(dict["Ramp down limit (MW)"], default = 1e6),
|
|
|
|
scalar(dict["Startup limit (MW)"], default = 1e6),
|
|
|
|
scalar(dict["Startup limit (MW)"], default = 1e6),
|
|
|
@ -291,6 +309,19 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
|
|
|
|
end
|
|
|
|
end
|
|
|
|
name_to_unit[unit_name] = unit
|
|
|
|
name_to_unit[unit_name] = unit
|
|
|
|
push!(units, unit)
|
|
|
|
push!(units, unit)
|
|
|
|
|
|
|
|
elseif lowercase(unit_type) === "profiled"
|
|
|
|
|
|
|
|
bus = name_to_bus[dict["Bus"]]
|
|
|
|
|
|
|
|
pu = ProfiledUnit(
|
|
|
|
|
|
|
|
unit_name,
|
|
|
|
|
|
|
|
bus,
|
|
|
|
|
|
|
|
timeseries(dict["Maximum power (MW)"]),
|
|
|
|
|
|
|
|
timeseries(dict["Cost (\$/MW)"]),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
push!(bus.profiled_units, pu)
|
|
|
|
|
|
|
|
push!(profiled_units, pu)
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
error("unit $unit_name has an invalid type")
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
# Read transmission lines
|
|
|
|
# Read transmission lines
|
|
|
@ -371,6 +402,8 @@ function _from_json(json; repair = true)::UnitCommitmentScenario
|
|
|
|
time = T,
|
|
|
|
time = T,
|
|
|
|
units_by_name = Dict(g.name => g for g in units),
|
|
|
|
units_by_name = Dict(g.name => g for g in units),
|
|
|
|
units = units,
|
|
|
|
units = units,
|
|
|
|
|
|
|
|
profiled_units_by_name = Dict(pu.name => pu for pu in profiled_units),
|
|
|
|
|
|
|
|
profiled_units = profiled_units,
|
|
|
|
isf = spzeros(Float64, length(lines), length(buses) - 1),
|
|
|
|
isf = spzeros(Float64, length(lines), length(buses) - 1),
|
|
|
|
lodf = spzeros(Float64, length(lines), length(lines)),
|
|
|
|
lodf = spzeros(Float64, length(lines), length(lines)),
|
|
|
|
)
|
|
|
|
)
|
|
|
|