Skip to content

Commit 4433c3c

Browse files
committed
Create separate folder for the rolling horizon playground
1 parent e813ef4 commit 4433c3c

File tree

6 files changed

+2620
-62
lines changed

6 files changed

+2620
-62
lines changed

rolling-horizon-ex2.jl

Lines changed: 0 additions & 62 deletions
This file was deleted.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[deps]
2+
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
3+
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
4+
DuckDB = "d2f5444f-75bc-4fdf-ac35-56f514c445e1"
5+
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
6+
TidierData = "fe2206b3-d496-4ee9-a338-6a095c4ece80"
7+
TulipaEnergyModel = "5d7bd171-d18e-45a5-9111-f1f11ac5d04d"
8+
TulipaIO = "7b3808b7-0819-42d4-885c-978ba173db11"
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
using CSV
2+
using DataFrames
3+
using DuckDB
4+
using Plots
5+
using TidierData
6+
using TulipaEnergyModel
7+
using TulipaIO
8+
9+
function create_connection()
10+
connection = DBInterface.connect(DuckDB.DB)
11+
schemas = TulipaEnergyModel.schema_per_table_name
12+
TulipaIO.read_csv_folder(
13+
connection,
14+
joinpath(@__DIR__, "..", "test", "inputs", "Rolling Horizon");
15+
schemas,
16+
)
17+
18+
return connection
19+
end
20+
21+
function create_energy_problem(connection)
22+
energy_problem = run_scenario(
23+
connection;
24+
show_log = false,
25+
model_file_name = joinpath(@__DIR__, "rolling-horizon.lp"),
26+
)
27+
28+
if !energy_problem.solved
29+
error("Infeasible")
30+
end
31+
32+
return energy_problem
33+
end
34+
35+
function plot_solution(connection)
36+
df_sql(s) = DataFrame(DuckDB.query(connection, s))
37+
big_table = df_sql("""
38+
WITH cte_outgoing AS (
39+
SELECT
40+
var.from_asset AS asset,
41+
var.time_block_start AS timestep,
42+
SUM(var.solution) AS solution,
43+
FROM var_flow AS var
44+
WHERE rep_period = 1 AND year = 2030
45+
GROUP BY asset, timestep
46+
), cte_incoming AS (
47+
SELECT
48+
var.to_asset AS asset,
49+
var.time_block_start AS timestep,
50+
SUM(var.solution) AS solution,
51+
FROM var_flow AS var
52+
WHERE rep_period = 1 AND year = 2030
53+
GROUP BY asset, timestep
54+
), cte_unified AS (
55+
SELECT
56+
cte_outgoing.asset,
57+
cte_outgoing.timestep,
58+
coalesce(cte_outgoing.solution) AS outgoing,
59+
coalesce(cte_incoming.solution) AS incoming,
60+
FROM cte_outgoing
61+
LEFT JOIN cte_incoming
62+
ON cte_outgoing.asset = cte_incoming.asset
63+
AND cte_outgoing.timestep = cte_incoming.timestep
64+
), cte_full_asset_data AS (
65+
SELECT
66+
cte_unified.*,
67+
asset.type,
68+
asset.group,
69+
FROM cte_unified
70+
LEFT JOIN asset
71+
ON cte_unified.asset = asset.asset
72+
)
73+
FROM cte_full_asset_data
74+
""")
75+
76+
timestep = range(extrema(big_table.timestep)...)
77+
78+
thermal = @chain big_table begin
79+
@filter(asset == "thermal")
80+
@arrange(timestep)
81+
@pull(outgoing)
82+
end
83+
solar = @chain big_table begin
84+
@filter(asset == "solar")
85+
@arrange(timestep)
86+
@pull(outgoing)
87+
end
88+
discharge = @chain big_table begin
89+
@filter(asset == "battery")
90+
@arrange(timestep)
91+
@pull(outgoing)
92+
end
93+
charge = @chain big_table begin
94+
@filter(asset == "battery")
95+
@arrange(timestep)
96+
@pull(incoming)
97+
end
98+
99+
horizon_length = length(timestep)
100+
@info "AAA" length(thermal) length(solar) length(discharge)
101+
y = hcat(thermal, solar, discharge)
102+
plot(;
103+
ylabel = "MW",
104+
xlims = (1, horizon_length),
105+
xticks = 1:12:horizon_length,
106+
size = (800, 150),
107+
)
108+
109+
areaplot!(timestep, y; label = ["thermal" "solar" "discharge"])
110+
return areaplot!(timestep, -charge; label = "charge")
111+
end
112+
113+
connection = create_connection()
114+
energy_problem = create_energy_problem(connection)
115+
plot_solution(connection)

rolling-horizon-ex1.jl renamed to rolling-horizon-playground/rolling-horizon-ex1.jl

File renamed without changes.
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
using CSV
2+
using DataFrames
3+
using DuckDB
4+
using TulipaEnergyModel
5+
using TulipaIO
6+
using Plots
7+
8+
function _validate_one_rep_period(connection)
9+
for row in DuckDB.query(
10+
connection,
11+
"SELECT year, max(rep_period) as num_rep_periods
12+
FROM rep_periods_data
13+
GROUP BY year
14+
",
15+
)
16+
if row.num_rep_periods > 1
17+
error("We should have only 1 rep period for rolling horizon")
18+
end
19+
end
20+
end
21+
22+
connection = DBInterface.connect(DuckDB.DB)
23+
schemas = TulipaEnergyModel.schema_per_table_name
24+
TulipaIO.read_csv_folder(
25+
connection,
26+
joinpath(@__DIR__, "..", "test", "inputs", "Rolling Horizon");
27+
schemas,
28+
)
29+
30+
_q(s) = DataFrame(DuckDB.query(connection, s))
31+
32+
# Manually run rolling horizon simulation
33+
try
34+
# MAKE SURE THAT num_rep_periods = 1, otherwise we don't know what to do yet
35+
# TODO: Create issue to add num_rep_periods to year_data
36+
# TODO: This should go to validation
37+
_validate_one_rep_period(connection)
38+
39+
move_forward = 24
40+
maximum_window_length = 48
41+
global energy_problem = run_rolling_horizon(
42+
connection,
43+
move_forward,
44+
maximum_window_length;
45+
show_log = false,
46+
model_file_name = "jump-test.lp",
47+
)
48+
49+
@info "Full run" energy_problem
50+
if energy_problem.solved
51+
# @info "Asset investment" _q("FROM var_assets_investment")
52+
@info "Storage" count(_q("FROM var_storage_level_rep_period").solution .> 0)
53+
@assert any(_q("FROM var_storage_level_rep_period").solution .> 0)
54+
# @info "Flow from solar" count(_q("FROM var_flow WHERE from_asset='Solar'").solution .> 0)
55+
# @info "Positive flows in the first 3 hours" _q(
56+
# "FROM var_flow WHERE solution > 0 AND time_block_start in (11, 12)",
57+
# )
58+
@info energy_problem
59+
else
60+
@warn "Infeasible"
61+
error("Infeasible")
62+
end
63+
64+
catch ex
65+
rethrow(ex)
66+
finally
67+
# close(connection)
68+
end
69+
70+
# Plotting
71+
df_sql(s) = DataFrame(DuckDB.query(connection, s))
72+
big_table = df_sql("""
73+
WITH cte_outgoing AS (
74+
SELECT
75+
rolsol.window_id,
76+
var.from_asset AS asset,
77+
var.time_block_start AS timestep,
78+
sum(rolsol.solution) AS solution
79+
FROM rolling_solution_var_flow AS rolsol
80+
LEFT JOIN full_var_flow AS var
81+
ON rolsol.var_id = var.id
82+
GROUP BY window_id, asset, timestep
83+
), cte_incoming AS (
84+
SELECT
85+
rolsol.window_id,
86+
var.to_asset AS asset,
87+
var.time_block_start AS timestep,
88+
sum(rolsol.solution) AS solution
89+
FROM rolling_solution_var_flow AS rolsol
90+
LEFT JOIN full_var_flow AS var
91+
ON rolsol.var_id = var.id
92+
GROUP BY window_id, asset, timestep
93+
), cte_unified AS (
94+
SELECT
95+
cte_outgoing.window_id,
96+
cte_outgoing.asset,
97+
cte_outgoing.timestep,
98+
coalesce(cte_outgoing.solution) AS outgoing,
99+
coalesce(cte_incoming.solution) AS incoming,
100+
FROM cte_outgoing
101+
LEFT JOIN cte_incoming
102+
ON cte_outgoing.window_id = cte_incoming.window_id
103+
AND cte_outgoing.asset = cte_incoming.asset
104+
AND cte_outgoing.timestep = cte_incoming.timestep
105+
), cte_full_asset_data AS (
106+
SELECT
107+
cte_unified.*,
108+
asset.type,
109+
FROM cte_unified
110+
LEFT JOIN asset
111+
ON cte_unified.asset = asset.asset
112+
)
113+
FROM cte_full_asset_data
114+
""")
115+
116+
num_windows = TulipaEnergyModel.get_num_rows(connection, "rolling_horizon_window")
117+
horizon_length = maximum(big_table.timestep)
118+
119+
big_table_grouped_per_window = groupby(big_table, :window_id)
120+
plt_vec = Plots.Plot[]
121+
for ((window_id,), window_table) in pairs(big_table_grouped_per_window)
122+
local timestep = range(extrema(window_table.timestep)...)
123+
124+
thermal = sort(window_table[window_table.asset.=="thermal", :], :timestep).outgoing
125+
solar = sort(window_table[window_table.asset.=="solar", :], :timestep).outgoing
126+
discharge = sort(window_table[window_table.asset.=="battery", :], :timestep).outgoing
127+
charge = sort(window_table[window_table.asset.=="battery", :], :timestep).incoming
128+
129+
y = hcat(thermal, solar, discharge)
130+
local plt = plot(; ylabel = "MW", xlims = (1, horizon_length), xticks = 1:12:horizon_length)
131+
label = window_id == 1 ? ["thermal" "solar" "discharge"] : false
132+
areaplot!(timestep, y; lab = label)
133+
label = window_id == 1 ? "charge" : false
134+
areaplot!(timestep, -charge; lab = label)
135+
push!(plt_vec, plt)
136+
end
137+
Plots.plot(plt_vec...; layout = (length(plt_vec), 1), size = (800, 150 * num_windows))
138+
plot!()
139+
140+
# TODO: fix naming of opt_window (just move_forward is enough)

0 commit comments

Comments
 (0)