Skip to content

Commit cb8ebb2

Browse files
gnawinabelsiqueira
andauthored
Add vintage flow sum constraint (#1292)
* Add vintage flow sum constraint * Add test * Typo * Update test/test-constraint-vintage-flow-sum.jl Co-authored-by: Abel Soares Siqueira <nepper271@gmail.com> * Apply review suggestions --------- Co-authored-by: Abel Soares Siqueira <nepper271@gmail.com>
1 parent f812ab1 commit cb8ebb2

5 files changed

Lines changed: 192 additions & 0 deletions

File tree

src/constraints/create.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ function compute_constraints_indices(connection)
3434
:flows_relationships,
3535
:dc_power_flow,
3636
:limit_decommission_compact_method,
37+
:vintage_flow_sum_semi_compact_method,
3738
)
3839
)
3940

src/constraints/vintage-flow.jl

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
export add_vintage_flow_sum_constraints!
2+
3+
"""
4+
add_vintage_flow_sum_constraints!(connection, model, variables, constraints)
5+
6+
Adds the vintage flow sum constraints to the model.
7+
"""
8+
function add_vintage_flow_sum_constraints!(connection, model, variables, constraints)
9+
let table_name = :vintage_flow_sum_semi_compact_method,
10+
cons = constraints[:vintage_flow_sum_semi_compact_method]
11+
12+
indices = _append_vintage_flow_data_to_indices(connection, table_name)
13+
14+
var_flow = variables[:flow].container
15+
var_vintage_flow = variables[:vintage_flow].container
16+
17+
attach_constraint!(
18+
model,
19+
cons,
20+
table_name,
21+
[
22+
@constraint(
23+
model,
24+
sum(var_vintage_flow[idx] for idx in row.var_vintage_flow_indices) ==
25+
var_flow[row.var_flow_id],
26+
base_name = "$table_name[$(row.from_asset),$(row.to_asset),$(row.year),$(row.rep_period),$(row.time_block_start):$(row.time_block_end)]"
27+
) for row in indices
28+
],
29+
)
30+
end
31+
32+
return
33+
end
34+
35+
function _append_vintage_flow_data_to_indices(connection, table_name)
36+
return DuckDB.query(
37+
connection,
38+
"SELECT
39+
cons.id,
40+
cons.from_asset,
41+
cons.to_asset,
42+
cons.year,
43+
cons.rep_period,
44+
cons.time_block_start,
45+
cons.time_block_end,
46+
ANY_VALUE(var_flow.id) AS var_flow_id,
47+
ARRAY_AGG(var_vintage_flow.id) AS var_vintage_flow_indices,
48+
FROM cons_$table_name AS cons
49+
LEFT JOIN var_flow
50+
ON cons.from_asset = var_flow.from_asset
51+
AND cons.to_asset = var_flow.to_asset
52+
AND cons.year = var_flow.year
53+
AND cons.rep_period = var_flow.rep_period
54+
AND cons.time_block_start = var_flow.time_block_start
55+
LEFT JOIN var_vintage_flow
56+
ON var_vintage_flow.from_asset = cons.from_asset
57+
AND var_vintage_flow.to_asset = cons.to_asset
58+
AND var_vintage_flow.milestone_year = cons.year
59+
AND var_vintage_flow.rep_period = cons.rep_period
60+
AND var_vintage_flow.time_block_start = cons.time_block_start
61+
GROUP BY cons.id, cons.from_asset, cons.to_asset, cons.year, cons.rep_period, cons.time_block_start, cons.time_block_end
62+
ORDER BY cons.id
63+
",
64+
)
65+
end

src/create-model.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,13 @@ function create_model(
204204
model_parameters,
205205
)
206206

207+
@timeit to "add_vintage_flow_sum_constraints!" add_vintage_flow_sum_constraints!(
208+
connection,
209+
model,
210+
variables,
211+
constraints,
212+
)
213+
207214
if model_file_name != ""
208215
@timeit to "save model file" JuMP.write_to_file(model, model_file_name)
209216
end

src/sql/create-constraints.sql

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,3 +651,28 @@ where
651651

652652
drop sequence id
653653
;
654+
655+
create sequence id start 1
656+
;
657+
658+
drop table if exists cons_vintage_flow_sum_semi_compact_method
659+
;
660+
661+
create table cons_vintage_flow_sum_semi_compact_method as
662+
select
663+
nextval('id') as id,
664+
from_asset,
665+
to_asset,
666+
year,
667+
rep_period,
668+
time_block_start,
669+
time_block_end,
670+
from
671+
var_flow
672+
left join asset on asset.asset = var_flow.from_asset
673+
where
674+
asset.investment_method = 'semi-compact'
675+
;
676+
677+
drop sequence id
678+
;
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
@testset "Test add_vintage_flow_sum_constraints!" begin
2+
# Setup a temporary DuckDB connection and model
3+
connection = DBInterface.connect(DuckDB.DB)
4+
model = JuMP.Model()
5+
6+
# Create mock tables for testing using register_data_frame
7+
# This first table is only necessary because we have a left join of var_flow with the asset table
8+
table_rows = [("input_1", "semi-compact"), ("input_2", "compact"), ("death_star", "simple")]
9+
asset = DataFrame(table_rows, [:asset, :investment_method])
10+
DuckDB.register_data_frame(connection, asset, "asset")
11+
12+
table_rows = [
13+
("input_1", "death_star", false),
14+
("input_2", "death_star", false),
15+
("death_star", "input_1", false),
16+
("death_star", "input_2", false),
17+
]
18+
flow = DataFrame(table_rows, [:from_asset, :to_asset, :is_transport])
19+
DuckDB.register_data_frame(connection, flow, "flow")
20+
21+
table_rows = [
22+
(1, "input_1", "death_star", 2025, 1, 1, 1),
23+
(2, "input_2", "death_star", 2025, 1, 1, 1),
24+
(3, "death_star", "input_1", 2025, 1, 1, 1),
25+
(4, "death_star", "input_2", 2025, 1, 1, 1),
26+
]
27+
var_flow = DataFrame(
28+
table_rows,
29+
[:id, :from_asset, :to_asset, :year, :rep_period, :time_block_start, :time_block_end],
30+
)
31+
DuckDB.register_data_frame(connection, var_flow, "var_flow")
32+
33+
table_rows = [
34+
(1, "input_1", "death_star", 2025, 2025, 1, 1, 1),
35+
(2, "input_1", "death_star", 2025, 2020, 1, 1, 1),
36+
]
37+
var_vintage_flow = DataFrame(
38+
table_rows,
39+
[
40+
:id,
41+
:from_asset,
42+
:to_asset,
43+
:milestone_year,
44+
:commission_year,
45+
:rep_period,
46+
:time_block_start,
47+
:time_block_end,
48+
],
49+
)
50+
DuckDB.register_data_frame(connection, var_vintage_flow, "var_vintage_flow")
51+
52+
variables = Dict{Symbol,TulipaEnergyModel.TulipaVariable}(
53+
key => TulipaEnergyModel.TulipaVariable(connection, "var_$key") for
54+
key in (:flow, :vintage_flow)
55+
)
56+
TulipaEnergyModel.add_flow_variables!(connection, model, variables)
57+
TulipaEnergyModel.add_vintage_flow_variables!(connection, model, variables)
58+
59+
table_rows = [(1, "input_1", "death_star", 2025, 1, 1, 1)]
60+
61+
cons_vintage_flow_sum_semi_compact_method = DataFrame(
62+
table_rows,
63+
[:id, :from_asset, :to_asset, :year, :rep_period, :time_block_start, :time_block_end],
64+
)
65+
DuckDB.register_data_frame(
66+
connection,
67+
cons_vintage_flow_sum_semi_compact_method,
68+
"cons_vintage_flow_sum_semi_compact_method",
69+
)
70+
71+
constraints = let key = :vintage_flow_sum_semi_compact_method
72+
Dict{Symbol,TulipaEnergyModel.TulipaConstraint}(
73+
key => TulipaEnergyModel.TulipaConstraint(connection, "cons_$key"),
74+
)
75+
end
76+
77+
TulipaEnergyModel.add_vintage_flow_sum_constraints!(connection, model, variables, constraints)
78+
79+
# Test the constraints
80+
var_flow = variables[:flow].container
81+
var_vintage_flow = variables[:vintage_flow].container
82+
83+
expected_con =
84+
[JuMP.@build_constraint(var_vintage_flow[1] + var_vintage_flow[2] == var_flow[1])]
85+
86+
observed_con =
87+
[JuMP.constraint_object(con) for con in model[:vintage_flow_sum_semi_compact_method]]
88+
89+
for (expected, observed) in zip(expected_con, observed_con)
90+
@test _is_constraint_equal(expected, observed)
91+
end
92+
93+
@test length(expected_con) == length(observed_con)
94+
end

0 commit comments

Comments
 (0)