Skip to content

Commit

Permalink
Add simple method transport investment (#829)
Browse files Browse the repository at this point in the history
* Change model

* Modify Norse data

* Update model

* Change is_transport to graph-flows-data

* Update src/create-model.jl

Co-authored-by: Abel Soares Siqueira <[email protected]>

* Add flows-fixed-cost into obj, and change data to 0

* Apply review suggestions

---------

Co-authored-by: Abel Soares Siqueira <[email protected]>
  • Loading branch information
gnawin and abelsiqueira authored Sep 30, 2024
1 parent 4a6cb38 commit 3598d66
Show file tree
Hide file tree
Showing 27 changed files with 1,527 additions and 1,511 deletions.
792 changes: 396 additions & 396 deletions benchmark/EU/flows-data.csv

Large diffs are not rendered by default.

792 changes: 396 additions & 396 deletions benchmark/EU/graph-flows-data.csv

Large diffs are not rendered by default.

788 changes: 394 additions & 394 deletions benchmark/EU/vintage-flows-data.csv

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/constraints/capacity.jl
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ function add_capacity_constraints!(

# - Lower limit for flows that are not transport assets
for row in eachrow(df_flows)
if !graph[row.from, row.to].is_transport[row.year]
if !graph[row.from, row.to].is_transport
JuMP.set_lower_bound(flow[row.index], 0.0)
end
end
Expand Down
121 changes: 46 additions & 75 deletions src/constraints/transport.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,103 +6,74 @@ add_transport_constraints!(model, graph, df_flows, flow, Ft, flows_investment)
Adds the transport flow constraints to the model.
"""

function add_transport_constraints!(model, graph, df_flows, flow, Ft, flows_investment)
function add_transport_constraints!(
model,
graph,
df_flows,
flow,
Ft,
accumulated_flows_export_units,
accumulated_flows_import_units,
flows_investment,
)

## Expressions used by transport flow constraints
# Filter df_flows to flows only for transport assets
df = filter([:from, :to] => (from, to) -> (from, to) Ft, df_flows; view = true)

# - Create upper limit of transport flow
upper_bound_transport_flow = [
if graph[row.from, row.to].investable[row.year]
@expression(
model,
profile_aggregation(
Statistics.mean,
graph[row.from, row.to].rep_periods_profiles,
row.year,
row.year,
("availability", row.rep_period),
row.timesteps_block,
1.0,
) *
graph[row.from, row.to].capacity *
(
graph[row.from, row.to].initial_export_units[row.year] +
flows_investment[row.year, (row.from, row.to)]
)
)
else
@expression(
model,
profile_aggregation(
Statistics.mean,
graph[row.from, row.to].rep_periods_profiles,
row.year,
row.year,
("availability", row.rep_period),
row.timesteps_block,
1.0,
) *
graph[row.from, row.to].capacity *
graph[row.from, row.to].initial_export_units[row.year]
)
end for row in eachrow(df_flows)
@expression(
model,
profile_aggregation(
Statistics.mean,
graph[row.from, row.to].rep_periods_profiles,
row.year,
row.year,
("availability", row.rep_period),
row.timesteps_block,
1.0,
) *
graph[row.from, row.to].capacity *
accumulated_flows_export_units[row.year, (row.from, row.to)]
) for row in eachrow(df)
]

# Create lower limit of transport flow
# - Create lower limit of transport flow
lower_bound_transport_flow = [
if graph[row.from, row.to].investable[row.year]
@expression(
model,
profile_aggregation(
Statistics.mean,
graph[row.from, row.to].rep_periods_profiles,
row.year,
row.year,
("availability", row.rep_period),
row.timesteps_block,
1.0,
) *
graph[row.from, row.to].capacity *
(
graph[row.from, row.to].initial_import_units[row.year] +
flows_investment[row.year, (row.from, row.to)]
)
)
else
@expression(
model,
profile_aggregation(
Statistics.mean,
graph[row.from, row.to].rep_periods_profiles,
row.year,
row.year,
("availability", row.rep_period),
row.timesteps_block,
1.0,
) *
graph[row.from, row.to].capacity *
graph[row.from, row.to].initial_import_units[row.year]
)
end for row in eachrow(df_flows)
@expression(
model,
profile_aggregation(
Statistics.mean,
graph[row.from, row.to].rep_periods_profiles,
row.year,
row.year,
("availability", row.rep_period),
row.timesteps_block,
1.0,
) *
graph[row.from, row.to].capacity *
accumulated_flows_import_units[row.year, (row.from, row.to)]
) for row in eachrow(df)
]

## Constraints that define bounds for a transport flow Ft
df = filter([:from, :to, :year] => (from, to, y) -> (from, to) Ft[y], df_flows; view = true)

# - Max transport flow limit
model[:max_transport_flow_limit] = [
@constraint(
model,
flow[row.index] upper_bound_transport_flow[row.index],
flow[row.index] upper_bound_transport_flow[idx],
base_name = "max_transport_flow_limit[($(row.from),$(row.to)),$(row.year),$(row.rep_period),$(row.timesteps_block)]"
) for row in eachrow(df)
) for (idx, row) in enumerate(eachrow(df))
]

# - Min transport flow limit
model[:min_transport_flow_limit] = [
@constraint(
model,
flow[row.index] -lower_bound_transport_flow[row.index],
flow[row.index] -lower_bound_transport_flow[idx],
base_name = "min_transport_flow_limit[($(row.from),$(row.to)),$(row.year),$(row.rep_period),$(row.timesteps_block)]"
) for row in eachrow(df)
) for (idx, row) in enumerate(eachrow(df))
]
end
52 changes: 51 additions & 1 deletion src/create-model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ function create_model(
As = filter_graph(graph, A, "storage", :type)
Ah = filter_graph(graph, A, "hub", :type)
Acv = filter_graph(graph, A, "conversion", :type)
Ft = Dict(y => filter_graph(graph, F, true, :is_transport, y) for y in Y)
Ft = filter_graph(graph, F, true, :is_transport)

# Create subsets of assets by investable
Ai = Dict(y => filter_graph(graph, A, true, :investable, y) for y in Y)
Expand Down Expand Up @@ -658,6 +658,9 @@ function create_model(
a in decommissionable_assets_using_compact_method
)

starting_year_flows_using_simple_method =
Dict((y, (u, v)) => y - graph[u, v].technical_lifetime + 1 for y in Y for (u, v) in Ft)

# Create a subset of decommissionable_assets_using_compact_method: existing assets invested in non-milestone years
existing_assets_by_year_using_compact_method = Dict(
y =>
Expand Down Expand Up @@ -756,6 +759,7 @@ function create_model(
0 <=
assets_decommission_compact_method[(a, y, v) in decommission_set_using_compact_method]
) #number of decommission asset units [N]
@variable(model, 0 flows_decommission_using_simple_method[y in Y, (u, v) in Ft]) #number of decommission flow units [N]

@variable(model, 0 assets_investment_energy[y in Y, a in Ase[y]Ai[y]]) #number of installed asset units for storage energy [N]
@variable(
Expand Down Expand Up @@ -1115,6 +1119,37 @@ function create_model(
@expression(model, sum(values(graph[a].initial_units[y])))
end for a in A for y in Y
]
## Expressions for transport assets
@expression(
model,
accumulated_investment_units_transport_using_simple_method[y Y, (u, v) Ft],
sum(
flows_investment[yy, (u, v)] for yy in Y if
(u, v) Fi[yy] && starting_year_flows_using_simple_method[(y, (u, v))] yy y
)
)
@expression(
model,
accumulated_decommission_units_transport_using_simple_method[y Y, (u, v) Ft],
sum(
flows_decommission_using_simple_method[yy, (u, v)] for
yy in Y if starting_year_flows_using_simple_method[(y, (u, v))] yy y
)
)
@expression(
model,
accumulated_flows_export_units[y Y, (u, v) Ft],
sum(values(graph[u, v].initial_export_units[y])) +
accumulated_investment_units_transport_using_simple_method[y, (u, v)] -
accumulated_decommission_units_transport_using_simple_method[y, (u, v)]
)
@expression(
model,
accumulated_flows_import_units[y Y, (u, v) Ft],
sum(values(graph[u, v].initial_import_units[y])) +
accumulated_investment_units_transport_using_simple_method[y, (u, v)] -
accumulated_decommission_units_transport_using_simple_method[y, (u, v)]
)
end

## Expressions for storage assets
Expand Down Expand Up @@ -1243,6 +1278,18 @@ function create_model(
)
)

flows_fixed_cost = @expression(
model,
sum(
graph[u, v].fixed_cost[y] / 2 *
graph[u, v].capacity *
(
accumulated_flows_export_units[y, (u, v)] +
accumulated_flows_import_units[y, (u, v)]
) for y in Y for (u, v) in Fi[y]
)
)

# Create a dict of intervals for milestone years
intervals_for_milestone_years = create_intervals_for_years(Y)

Expand Down Expand Up @@ -1290,6 +1337,7 @@ function create_model(
storage_assets_energy_investment_cost +
storage_assets_energy_fixed_cost +
flows_investment_cost +
flows_fixed_cost +
flows_variable_cost +
units_on_cost
)
Expand Down Expand Up @@ -1367,6 +1415,8 @@ function create_model(
df_flows,
flow,
Ft,
accumulated_flows_export_units,
accumulated_flows_import_units,
flows_investment,
)

Expand Down
2 changes: 1 addition & 1 deletion src/input-schemas.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const schemas = (
:from_asset => "VARCHAR", # Name of Asset
:to_asset => "VARCHAR", # Name of Asset
:carrier => "VARCHAR", # (Optional?) Energy carrier
:is_transport => "BOOLEAN", # Whether a transport flow
:capacity => "DOUBLE",
:technical_lifetime => "INTEGER",
:economic_lifetime => "INTEGER",
Expand Down Expand Up @@ -118,7 +119,6 @@ const schemas = (
:to_asset => "VARCHAR", # Name of Asset
:year => "INTEGER",
:active => "BOOLEAN", # Active or decomissioned
:is_transport => "BOOLEAN", # Whether a transport flow
:investable => "BOOLEAN", # Whether able to invest
:investment_integer => "BOOLEAN", # Whether investment is integer or continuous
:variable_cost => "DOUBLE", # kEUR/MWh
Expand Down
7 changes: 1 addition & 6 deletions src/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,7 @@ function create_internal_structures(connection)
from_asset = row.from_asset,
to_asset = row.to_asset,
),
_get_stuff_year(
"flows_data",
"is_transport";
from_asset = row.from_asset,
to_asset = row.to_asset,
),
row.is_transport,
_get_stuff_year(
"flows_data",
"investable";
Expand Down
2 changes: 1 addition & 1 deletion src/structures.jl
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ Structure to hold the flow data in the graph.
mutable struct GraphFlowData
carrier::String
active::Dict{Int,Bool}
is_transport::Dict{Int,Bool}
is_transport::Bool
investable::Dict{Int,Bool}
investment_integer::Dict{Int,Bool}
technical_lifetime::Float64
Expand Down
34 changes: 17 additions & 17 deletions test/inputs/Multi-year Investments/flows-data.csv
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
asset_name,asset_name,{true;false},,year,{true;false},{true;false},{true;false},kEUR/MWh,kEUR/MW/year,kEUR/MW/year,MW,MW,MW,p.u.
from_asset,to_asset,active,year,commission_year,is_transport,investable,investment_integer,variable_cost,investment_cost,fixed_cost,investment_limit,initial_export_units,initial_import_units,efficiency
ocgt,demand,true,2030,2030,false,false,false,0.07,0,0.1,,0,0,0
ccgt,demand,true,2030,2028,true,false,false,0.05,0,0.1,,1,1,0
ccgt,demand,true,2030,2030,true,true,false,0.05,0,0.1,100,0,0,0
battery,demand,true,2030,2030,false,false,false,0.0,0,0.1,,0,0,0.95
demand,battery,true,2030,2030,false,false,false,0.0,0,0.1,,0,0,0.95
wind,demand,true,2030,2030,false,false,false,0.001,0,0.1,,0,0,0
solar,demand,true,2030,2030,false,false,false,0,0,0.1,,0,0,0
ens,demand,true,2030,2030,false,false,false,0.18,0,0.1,,0,0,0
ocgt,demand,true,2050,2030,false,false,false,0.07,0,0.1,,0,0,0
ccgt,demand,true,2050,2050,true,true,false,0.05,0,0.1,100,0,0,0
battery,demand,true,2050,2030,false,false,false,0.0,0,0.1,,0,0,0.95
demand,battery,true,2050,2030,false,false,false,0.0,0,0.1,,0,0,0.95
wind,demand,true,2050,2030,false,false,false,0.001,0,0.1,,0,0,0
solar,demand,true,2050,2030,false,false,false,0,0,0.1,,0,0,0
ens,demand,false,2050,2030,false,false,false,0.18,0,0.1,,0,0,0
asset_name,asset_name,{true;false},,year,{true;false},{true;false},kEUR/MWh,kEUR/MW/year,kEUR/MW/year,MW,units,units,p.u.
from_asset,to_asset,active,year,commission_year,investable,investment_integer,variable_cost,investment_cost,fixed_cost,investment_limit,initial_export_units,initial_import_units,efficiency
ocgt,demand,true,2030,2030,false,false,0.07,0,0.1,,0,0,0
ccgt,demand,true,2030,2028,false,false,0.05,0,0.1,,1,1,0
ccgt,demand,true,2030,2030,true,false,0.05,0,0.1,100,0,0,0
battery,demand,true,2030,2030,false,false,0,0,0.1,,0,0,0.95
demand,battery,true,2030,2030,false,false,0,0,0.1,,0,0,0.95
wind,demand,true,2030,2030,false,false,0.001,0,0.1,,0,0,0
solar,demand,true,2030,2030,false,false,0,0,0.1,,0,0,0
ens,demand,true,2030,2030,false,false,0.18,0,0.1,,0,0,0
ocgt,demand,true,2050,2030,false,false,0.07,0,0.1,,0,0,0
ccgt,demand,true,2050,2050,true,false,0.05,0,0.1,100,0,0,0
battery,demand,true,2050,2030,false,false,0,0,0.1,,0,0,0.95
demand,battery,true,2050,2030,false,false,0,0,0.1,,0,0,0.95
wind,demand,true,2050,2030,false,false,0.001,0,0.1,,0,0,0
solar,demand,true,2050,2030,false,false,0,0,0.1,,0,0,0
ens,demand,false,2050,2030,false,false,0.18,0,0.1,,0,0,0
18 changes: 9 additions & 9 deletions test/inputs/Multi-year Investments/graph-flows-data.csv
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
asset_name,asset_name,,MW,year,year,
from_asset,to_asset,carrier,capacity,technical_lifetime,economic_lifetime,discount_rate
ocgt,demand,electricity,0,10,1,0.02
ccgt,demand,electricity,100,10,1,0.02
battery,demand,electricity,0,10,1,0.02
demand,battery,electricity,0,10,1,0.02
wind,demand,electricity,0,10,1,0.02
solar,demand,electricity,0,10,1,0.02
ens,demand,electricity,0,10,1,0.02
asset_name,asset_name,,{true;false},MW,year,year,
from_asset,to_asset,carrier,is_transport,capacity,technical_lifetime,economic_lifetime,discount_rate
ocgt,demand,electricity,false,0,10,1,0.02
ccgt,demand,electricity,true,100,10,1,0.02
battery,demand,electricity,false,0,10,1,0.02
demand,battery,electricity,false,0,10,1,0.02
wind,demand,electricity,false,0,10,1,0.02
solar,demand,electricity,false,0,10,1,0.02
ens,demand,electricity,false,0,10,1,0.02
28 changes: 14 additions & 14 deletions test/inputs/Multi-year Investments/vintage-flows-data.csv
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
asset_name,asset_name,year,kEUR/MW/year,kEUR/MW
from_asset,to_asset,commission_year,fixed_cost,investment_cost
ocgt,demand,2030,0.1,350
ccgt,demand,2030,0.1,350
battery,demand,2030,0.1,350
demand,battery,2030,0.1,350
wind,demand,2030,0.1,350
solar,demand,2030,0.1,350
ens,demand,2030,0.1,350
ocgt,demand,2050,0.1,350
ccgt,demand,2050,0.1,350
battery,demand,2050,0.1,350
demand,battery,2050,0.1,350
wind,demand,2030,0.1,350
solar,demand,2050,0.1,350
ens,demand,2050,0.1,350
ocgt,demand,2030,0,350
ccgt,demand,2030,0,350
battery,demand,2030,0,350
demand,battery,2030,0,350
wind,demand,2030,0,350
solar,demand,2030,0,350
ens,demand,2030,0,350
ocgt,demand,2050,0,350
ccgt,demand,2050,0,350
battery,demand,2050,0,350
demand,battery,2050,0,350
wind,demand,2030,0,350
solar,demand,2050,0,350
ens,demand,2050,0,350
Loading

0 comments on commit 3598d66

Please sign in to comment.