Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/config/configure_settings.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ function default_settings()
AutoCreateNodes = false,
AutoCreateLocations = true,
Retrofitting = false,
CapacityReserveMargin = Dict{Symbol,Float64}(),
DualExportsEnabled = true
)
end
Expand Down
1 change: 1 addition & 0 deletions src/load_inputs/process_data.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ function process_data(data::AbstractDict{Symbol,Any})
validate_data(data)
check_and_convert_inf!(data)
check_and_convert_symbol!(data, :startup_fuel_balance_id)
check_and_convert_symbol!(data, :capacity_reserve_margin_id)
haskey(data, :demand) && check_and_convert_demand!(data)
haskey(data, :constraints) && check_and_convert_constraints!(data)
haskey(data, :rhs_policy) && check_and_convert_rhs_policy!(data)
Expand Down
16 changes: 16 additions & 0 deletions src/model/constraints/capacity_reserve_margin.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Base.@kwdef mutable struct CapacityReserveMarginConstraint <: PlanningConstraint
value::Union{Missing,Vector{Float64}} = missing
constraint_dual::Union{Missing,Vector{Float64}} = missing
constraint_ref::Union{Missing,JuMPConstraint} = missing
end

function add_model_constraint!(ct::CapacityReserveMarginConstraint, system::System, model::Model)

ct.constraint_ref = @constraint(
model,
[k in keys(system.settings.CapacityReserveMargin)],
model[:eCapacityReserveMargin][k] >= 0.0
)

return nothing
end
6 changes: 6 additions & 0 deletions src/model/constraints/constraints_utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ constraint_ref(c::AbstractTypeConstraint) = c.constraint_ref;

function add_constraints_by_type!(system::System, model::Model, constraint_type::DataType)

for c in all_constraints(system)
if isa(c, constraint_type)
add_model_constraint!(c, system, model)
end
end

for n in system.locations
add_constraints_by_type!(n, model, constraint_type)
end
Expand Down
57 changes: 57 additions & 0 deletions src/model/generate_model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ end

function planning_model!(system::System, model::Model)

if !isempty(system.settings.CapacityReserveMargin)
@info(" -- Including capacity reserve margins: $(keys(system.settings.CapacityReserveMargin))")
prepare_capacity_reserve_margin!(system, model)
end

planning_model!.(system.locations, Ref(model))

planning_model!.(system.assets, Ref(model))
Expand Down Expand Up @@ -416,4 +421,56 @@ function validate_existing_capacity(asset::AbstractAsset)
end
end
end
end

function prepare_capacity_reserve_margin!(system::System, model::Model)

capacity_reserve_margin_nodes = get_capacity_reserve_margin_nodes(system)

capacity_reserve_margin_ids = keys(system.settings.CapacityReserveMargin)

if capacity_reserve_margin_ids != keys(capacity_reserve_margin_nodes)
missing_ids = setdiff(capacity_reserve_margin_ids, keys(capacity_reserve_margin_nodes))
extra_ids = setdiff(keys(capacity_reserve_margin_nodes), capacity_reserve_margin_ids)
if !isempty(missing_ids)
msg = " ++ Capacity reserve margin ids defined in settings but not associated with any node: $(collect(missing_ids)). Please double check the input data."
@error(msg)
end
if !isempty(extra_ids)
msg = " ++ Capacity reserve margin ids associated with nodes but not defined in settings: $(collect(extra_ids)). Please double check the input data."
@error(msg)
end
end

peak_demand = Dict{Symbol,Float64}(k=> maximum(sum(demand(n) for n in capacity_reserve_margin_nodes[k])) for k in capacity_reserve_margin_ids)

required_capacity = Dict{Symbol,Float64}(k=> (1 + system.settings.CapacityReserveMargin[k]) * peak_demand[k] for k in capacity_reserve_margin_ids)

if any(system.settings.CapacityReserveMargin[k] == 0.0 for k in capacity_reserve_margin_ids)
msg = " ++ Capacity reserve margin with id: $k is set to 0.0"
@warn(msg)
end

@expression(model, eCapacityReserveMargin[k in capacity_reserve_margin_ids], -required_capacity[k]*AffExpr(1))

push!(system.constraints, CapacityReserveMarginConstraint())

return nothing

end

function get_capacity_reserve_margin_nodes(system::System)
capacity_reserve_margin_nodes = Dict{Symbol,Vector{Node}}()
nodes = get_nodes(system)
for n in nodes
crm_id = capacity_reserve_margin_id(n)
if !ismissing(crm_id)
if !haskey(capacity_reserve_margin_nodes,crm_id)
capacity_reserve_margin_nodes[crm_id] = [n]
else
push!(capacity_reserve_margin_nodes[crm_id], n)
end
end
end
return capacity_reserve_margin_nodes
end
14 changes: 14 additions & 0 deletions src/model/networks/edge.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ macro AbstractEdgeBaseAttributes()
can_retrofit::Bool = $edge_defaults[:can_retrofit]
capacity::Union{JuMPVariable,AffExpr,Float64} = AffExpr(0.0)
capacity_size::Float64 = $edge_defaults[:capacity_size]
capacity_reserve_margin_id::Union{Symbol,Missing} = $edge_defaults[:capacity_reserve_margin_id]
capacity_reserve_margin_derate_factor::Float64 = $edge_defaults[:capacity_reserve_margin_derate_factor]
capital_recovery_period::Int64 = $edge_defaults[:capital_recovery_period]
constraints::Vector{AbstractTypeConstraint} = Vector{AbstractTypeConstraint}()
distance::Float64 = $edge_defaults[:distance]
Expand Down Expand Up @@ -196,6 +198,8 @@ can_retire(e::AbstractEdge) = e.can_retire;
can_retrofit(e::AbstractEdge) = e.can_retrofit;
capacity(e::AbstractEdge) = e.capacity;
capacity_size(e::AbstractEdge) = e.capacity_size;
capacity_reserve_margin_id(e::AbstractEdge) = e.capacity_reserve_margin_id;
capacity_reserve_margin_derate_factor(e::AbstractEdge) = e.capacity_reserve_margin_derate_factor;
capital_recovery_period(e::AbstractEdge) = e.capital_recovery_period;
commodity_type(e::AbstractEdge{T}) where {T} = T;
end_vertex(e::AbstractEdge) = e.end_vertex;
Expand Down Expand Up @@ -303,6 +307,16 @@ function planning_model!(e::AbstractEdge, model::Model)

if has_capacity(e)

if !ismissing(capacity_reserve_margin_id(e))
if capacity_reserve_margin_id(e) ∈ axes(model[:eCapacityReserveMargin])[1]
add_to_expression!(model[:eCapacityReserveMargin][capacity_reserve_margin_id(e)],
capacity_reserve_margin_derate_factor(e) * capacity(e)
)
else
error("Edge $(id(e)) is associated with an undefined capacity reserve margin constraint. Please double check the input data.")
end
end

if !can_expand(e)
fix(new_units(e), 0.0; force = true)
else
Expand Down
3 changes: 3 additions & 0 deletions src/model/networks/node.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
macro AbstractNodeBaseAttributes()
node_defaults = node_default_data()
esc(quote
capacity_reserve_margin_id::Union{Symbol,Missing} = $node_defaults[:capacity_reserve_margin_id]
demand::Vector{Float64} = Vector{Float64}()
min_nsd::Vector{Float64} = $node_defaults[:min_nsd]
max_nsd::Vector{Float64} = $node_defaults[:max_nsd]
Expand Down Expand Up @@ -73,6 +74,7 @@ function make_node(data::AbstractDict{Symbol,Any}, time_data::TimeData, commodit
_node = Node{commodity}(;
id = id,
timedata = time_data,
capacity_reserve_margin_id = get(data, :capacity_reserve_margin_id, missing),
demand = get(data, :demand, Vector{Float64}()),
max_nsd = get(data, :max_nsd, [0.0]),
max_supply = get(data, :max_supply, [0.0]),
Expand All @@ -91,6 +93,7 @@ Node(data::AbstractDict{Symbol,Any}, time_data::TimeData, commodity::DataType) =
make_node(data, time_data, commodity)

######### Node interface #########
capacity_reserve_margin_id(n::Node) = n.capacity_reserve_margin_id;
commodity_type(n::Node{T}) where {T} = T;
demand(n::Node) = n.demand;
# demand(n::Node, t::Int64) = length(demand(n)) == 1 ? demand(n)[1] : demand(n)[t];
Expand Down
6 changes: 5 additions & 1 deletion src/model/system.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ mutable struct System <: AbstractSystem
assets::Vector{AbstractAsset}
locations::Vector{Union{Node, Location}}
input_data::Vector{Dict{Symbol,Any}}
constraints::Vector{AbstractTypeConstraint}
end

all_constraints(system::System) = system.constraints

"""
asset_ids(system::System; source::String="assets")

Expand Down Expand Up @@ -105,7 +108,8 @@ function empty_system(data_dirpath::String)
Dict{Symbol,TimeData}(),
[],
[],
[]
[],
Vector{AbstractTypeConstraint}(),
)
end

Expand Down
3 changes: 3 additions & 0 deletions src/utilities/default_data.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ function edge_default_data()
:can_expand => false,
:can_retire => false,
:can_retrofit => false,
:capacity_reserve_margin_id => missing,
:capacity_reserve_margin_derate_factor => 1.0,
:is_retrofit => false,
:capacity_size => 1.0,
:existing_capacity => 0.0,
Expand Down Expand Up @@ -96,6 +98,7 @@ function node_default_data()
:id => missing,
:timedata => missing,
:location => missing,
:capacity_reserve_margin_id => missing,
:constraints => Dict{Symbol,Bool}(),
:demand => Float64[],
:max_nsd => [0.0],
Expand Down
Loading