From 5deb5a3853c83ad7c05d8df596c718abf53a0fc4 Mon Sep 17 00:00:00 2001 From: Abel Soares Siqueira Date: Mon, 11 Dec 2023 11:02:19 +0100 Subject: [PATCH 1/3] Precompute summation indices for the model expressions --- src/create-model.jl | 108 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 89 insertions(+), 19 deletions(-) diff --git a/src/create-model.jl b/src/create-model.jl index 92c5a3fc..134af9c2 100644 --- a/src/create-model.jl +++ b/src/create-model.jl @@ -1,5 +1,8 @@ export create_model!, create_model +const TupleAssetRPTimeBlock = Tuple{String,Int,TimeBlock} +const TupleDurationFlowTimeBlock = Tuple{Float64,Tuple{String,String},TimeBlock} + """ create_model!(energy_problem) @@ -24,7 +27,7 @@ function create_model(graph, representative_periods, constraints_partitions; wri ## Helper functions # Computes the duration of the `block` that is within the `period`, and # multiply by the resolution of the representative period `rp`. - # It is equivalent to finding the indexes of these values in the matrix. + # It is equivalent to finding the indices of these values in the matrix. function duration(B1, B2, rp) return length(B1 ∩ B2) * representative_periods[rp].resolution end @@ -122,14 +125,85 @@ function create_model(graph, representative_periods, constraints_partitions; wri ## Objective function @objective(model, Min, assets_investment_cost + flows_investment_cost + flows_variable_cost) + function add_to_flow_sum_indices!(flow_sum_indices, a, rp, B, f) + for B_flow ∈ graph[f...].partitions[rp] + if B_flow[end] < B[1] + continue + end + d = duration(B, B_flow, rp) + if d != 0 + push!(flow_sum_indices, (d, f, B_flow)) + end + if B_flow[1] > B[end] + break + end + end + end + + flow_sum_indices_incoming_lowest = + Dict{TupleAssetRPTimeBlock,Vector{TupleDurationFlowTimeBlock}}() + flow_sum_indices_outgoing_lowest = + Dict{TupleAssetRPTimeBlock,Vector{TupleDurationFlowTimeBlock}}() + flow_sum_indices_incoming_highest = + Dict{TupleAssetRPTimeBlock,Vector{TupleDurationFlowTimeBlock}}() + flow_sum_indices_outgoing_highest = + Dict{TupleAssetRPTimeBlock,Vector{TupleDurationFlowTimeBlock}}() + for a ∈ A, rp ∈ RP + for B ∈ Pl[(a, rp)] + flow_sum_indices_incoming_lowest[a, rp, B] = TupleDurationFlowTimeBlock[] + flow_sum_indices_outgoing_lowest[a, rp, B] = TupleDurationFlowTimeBlock[] + for u ∈ inneighbor_labels(graph, a) + add_to_flow_sum_indices!( + flow_sum_indices_incoming_lowest[a, rp, B], + a, + rp, + B, + (u, a), + ) + end + + for v ∈ outneighbor_labels(graph, a) + add_to_flow_sum_indices!( + flow_sum_indices_outgoing_lowest[a, rp, B], + a, + rp, + B, + (a, v), + ) + end + end + for B ∈ Ph[(a, rp)] + flow_sum_indices_incoming_highest[a, rp, B] = TupleDurationFlowTimeBlock[] + flow_sum_indices_outgoing_highest[a, rp, B] = TupleDurationFlowTimeBlock[] + for u ∈ inneighbor_labels(graph, a) + add_to_flow_sum_indices!( + flow_sum_indices_incoming_highest[a, rp, B], + a, + rp, + B, + (u, a), + ) + end + + for v ∈ outneighbor_labels(graph, a) + add_to_flow_sum_indices!( + flow_sum_indices_outgoing_highest[a, rp, B], + a, + rp, + B, + (a, v), + ) + end + end + end + ## Expressions for balance constraints @expression( model, incoming_flow_lowest_resolution[a ∈ A, rp ∈ RP, B ∈ Pl[(a, rp)]], sum( - duration(B, B_flow, rp) * flow[(u, a), rp, B_flow] for - u in inneighbor_labels(graph, a), B_flow ∈ graph[u, a].partitions[rp] if - B_flow[end] ≥ B[1] && B[end] ≥ B_flow[1] + d * flow[f, rp, B_flow] for + (d, f, B_flow) ∈ flow_sum_indices_incoming_lowest[(a, rp, B)] ) ) @@ -137,9 +211,8 @@ function create_model(graph, representative_periods, constraints_partitions; wri model, outgoing_flow_lowest_resolution[a ∈ A, rp ∈ RP, B ∈ Pl[(a, rp)]], sum( - duration(B, B_flow, rp) * flow[(a, v), rp, B_flow] for - v in outneighbor_labels(graph, a), B_flow ∈ graph[a, v].partitions[rp] if - B_flow[end] ≥ B[1] && B[end] ≥ B_flow[1] + d * flow[f, rp, B_flow] for + (d, f, B_flow) ∈ flow_sum_indices_outgoing_lowest[(a, rp, B)] ) ) @@ -147,18 +220,17 @@ function create_model(graph, representative_periods, constraints_partitions; wri model, incoming_flow_lowest_resolution_w_efficiency[a ∈ A, rp ∈ RP, B ∈ Pl[(a, rp)]], sum( - duration(B, B_flow, rp) * flow[(u, a), rp, B_flow] * graph[u, a].efficiency for - u in inneighbor_labels(graph, a), B_flow ∈ graph[u, a].partitions[rp] if - B_flow[end] ≥ B[1] && B[end] ≥ B_flow[1] + d * flow[f, rp, B_flow] * graph[f...].efficiency for + (d, f, B_flow) ∈ flow_sum_indices_incoming_lowest[(a, rp, B)] ) ) + @expression( model, outgoing_flow_lowest_resolution_w_efficiency[a ∈ A, rp ∈ RP, B ∈ Pl[(a, rp)]], sum( - duration(B, B_flow, rp) * flow[(a, v), rp, B_flow] / graph[a, v].efficiency for - v in outneighbor_labels(graph, a), B_flow ∈ graph[a, v].partitions[rp] if - B_flow[end] ≥ B[1] && B[end] ≥ B_flow[1] + d * flow[f, rp, B_flow] / graph[f...].efficiency for + (d, f, B_flow) ∈ flow_sum_indices_outgoing_lowest[(a, rp, B)] ) ) @@ -227,9 +299,8 @@ function create_model(graph, representative_periods, constraints_partitions; wri model, incoming_flow_highest_resolution[a ∈ A, rp ∈ RP, B ∈ Ph[(a, rp)]], sum( - duration(B, B_flow, rp) * flow[(u, a), rp, B_flow] for - u in inneighbor_labels(graph, a), B_flow ∈ graph[u, a].partitions[rp] if - B_flow[end] ≥ B[1] && B[end] ≥ B_flow[1] + d * flow[f, rp, B_flow] for + (d, f, B_flow) in flow_sum_indices_incoming_highest[a, rp, B] ) ) @@ -237,9 +308,8 @@ function create_model(graph, representative_periods, constraints_partitions; wri model, outgoing_flow_highest_resolution[a ∈ A, rp ∈ RP, B ∈ Ph[(a, rp)]], sum( - duration(B, B_flow, rp) * flow[(a, v), rp, B_flow] for - v in outneighbor_labels(graph, a), B_flow ∈ graph[a, v].partitions[rp] if - B_flow[end] ≥ B[1] && B[end] ≥ B_flow[1] + d * flow[f, rp, B_flow] for + (d, f, B_flow) in flow_sum_indices_outgoing_highest[a, rp, B] ) ) From c0b12dda469466940b6de32a34f0c804791fe0d3 Mon Sep 17 00:00:00 2001 From: Abel Soares Siqueira Date: Mon, 18 Dec 2023 15:47:31 +0100 Subject: [PATCH 2/3] Collect assets and flows in the model to make it faster to evaluate presence in the set --- src/create-model.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/create-model.jl b/src/create-model.jl index 134af9c2..fbc8f8d9 100644 --- a/src/create-model.jl +++ b/src/create-model.jl @@ -56,10 +56,10 @@ function create_model(graph, representative_periods, constraints_partitions; wri end ## Sets unpacking - A = labels(graph) - F = edge_labels(graph) - filter_assets(key, value) = Iterators.filter(a -> getfield(graph[a], key) == value, A) - filter_flows(key, value) = Iterators.filter(f -> getfield(graph[f...], key) == value, F) + A = labels(graph) |> collect + F = edge_labels(graph) |> collect + filter_assets(key, value) = filter(a -> getfield(graph[a], key) == value, A) + filter_flows(key, value) = filter(f -> getfield(graph[f...], key) == value, F) Ac = filter_assets(:type, "consumer") Ap = filter_assets(:type, "producer") From 4dc6be59105de95880806ade9fc8e2b101609107 Mon Sep 17 00:00:00 2001 From: Abel Soares Siqueira Date: Mon, 18 Dec 2023 15:51:21 +0100 Subject: [PATCH 3/3] Perform more effective search to build indices sets --- src/create-model.jl | 119 +++++++++++++++++++++++++------------------- 1 file changed, 67 insertions(+), 52 deletions(-) diff --git a/src/create-model.jl b/src/create-model.jl index fbc8f8d9..70d42794 100644 --- a/src/create-model.jl +++ b/src/create-model.jl @@ -3,6 +3,32 @@ export create_model!, create_model const TupleAssetRPTimeBlock = Tuple{String,Int,TimeBlock} const TupleDurationFlowTimeBlock = Tuple{Float64,Tuple{String,String},TimeBlock} +function add_to_flow!(flow_sum_indices, graph, representative_periods, a, rp, P, f) + search_start_index = 1 + flow_partitions = graph[f...].partitions[rp] + num_flow_partitions = length(flow_partitions) + for B ∈ P + # Update search_start_index + while last(flow_partitions[search_start_index]) < first(B) + search_start_index += 1 + if search_start_index > num_flow_partitions + break + end + end + last_B = last(B) + for j = search_start_index:num_flow_partitions + B_flow = flow_partitions[j] + d = length(B ∩ B_flow) * representative_periods[rp].resolution + if d != 0 + push!(flow_sum_indices[a, rp, B], (d, f, B_flow)) + end + if first(B_flow) > last_B + break + end + end + end +end + """ create_model!(energy_problem) @@ -125,21 +151,6 @@ function create_model(graph, representative_periods, constraints_partitions; wri ## Objective function @objective(model, Min, assets_investment_cost + flows_investment_cost + flows_variable_cost) - function add_to_flow_sum_indices!(flow_sum_indices, a, rp, B, f) - for B_flow ∈ graph[f...].partitions[rp] - if B_flow[end] < B[1] - continue - end - d = duration(B, B_flow, rp) - if d != 0 - push!(flow_sum_indices, (d, f, B_flow)) - end - if B_flow[1] > B[end] - break - end - end - end - flow_sum_indices_incoming_lowest = Dict{TupleAssetRPTimeBlock,Vector{TupleDurationFlowTimeBlock}}() flow_sum_indices_outgoing_lowest = @@ -152,48 +163,52 @@ function create_model(graph, representative_periods, constraints_partitions; wri for B ∈ Pl[(a, rp)] flow_sum_indices_incoming_lowest[a, rp, B] = TupleDurationFlowTimeBlock[] flow_sum_indices_outgoing_lowest[a, rp, B] = TupleDurationFlowTimeBlock[] - for u ∈ inneighbor_labels(graph, a) - add_to_flow_sum_indices!( - flow_sum_indices_incoming_lowest[a, rp, B], - a, - rp, - B, - (u, a), - ) - end - - for v ∈ outneighbor_labels(graph, a) - add_to_flow_sum_indices!( - flow_sum_indices_outgoing_lowest[a, rp, B], - a, - rp, - B, - (a, v), - ) - end end for B ∈ Ph[(a, rp)] flow_sum_indices_incoming_highest[a, rp, B] = TupleDurationFlowTimeBlock[] flow_sum_indices_outgoing_highest[a, rp, B] = TupleDurationFlowTimeBlock[] - for u ∈ inneighbor_labels(graph, a) - add_to_flow_sum_indices!( - flow_sum_indices_incoming_highest[a, rp, B], - a, - rp, - B, - (u, a), - ) - end + end - for v ∈ outneighbor_labels(graph, a) - add_to_flow_sum_indices!( - flow_sum_indices_outgoing_highest[a, rp, B], - a, - rp, - B, - (a, v), - ) - end + for u ∈ inneighbor_labels(graph, a) + add_to_flow!( + flow_sum_indices_incoming_lowest, + graph, + representative_periods, + a, + rp, + Pl[(a, rp)], + (u, a), + ) + add_to_flow!( + flow_sum_indices_incoming_highest, + graph, + representative_periods, + a, + rp, + Ph[(a, rp)], + (u, a), + ) + end + + for v ∈ outneighbor_labels(graph, a) + add_to_flow!( + flow_sum_indices_outgoing_lowest, + graph, + representative_periods, + a, + rp, + Pl[(a, rp)], + (a, v), + ) + add_to_flow!( + flow_sum_indices_outgoing_highest, + graph, + representative_periods, + a, + rp, + Ph[(a, rp)], + (a, v), + ) end end