Skip to content

Commit

Permalink
Merge branch 'sankey_branch' of https://github.com/TomFer97/EnergyCom…
Browse files Browse the repository at this point in the history
…munity.jl into business_plan_plot
  • Loading branch information
TomFer97 committed Nov 13, 2023
2 parents ccb167b + 181b7d7 commit 957ff03
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 78 deletions.
8 changes: 7 additions & 1 deletion docs/src/examples/example_aggregated_non_cooperative.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,10 @@ print_summary(ANC_Model)
save_summary(ANC_Model, output_file_isolated)

# Plot the sankey plot of resources
plot_sankey(ANC_Model)
plot_sankey(ANC_Model)

# DataFrame of the business plan
business_plan(ANC_Model)

# plot business plan
business_plan_plot(ANC_Model)
8 changes: 7 additions & 1 deletion docs/src/examples/example_cooperative.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,10 @@ print_summary(CO_Model)
save_summary(CO_Model, output_file_isolated)

# Plot the sankey plot of resources
plot_sankey(CO_Model)
plot_sankey(CO_Model)

# DataFrame of the business plan
business_plan(CO_Model)

# plot business plan
business_plan_plot(CO_Model)
8 changes: 7 additions & 1 deletion docs/src/examples/example_non_cooperative.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,10 @@ print_summary(NC_Model)
save_summary(NC_Model, output_file_isolated)

# Plot the sankey plot of resources
plot_sankey(NC_Model)
plot_sankey(NC_Model)

# DataFrame of the business plan
business_plan(NC_Model)

# plot business plan
business_plan_plot(NC_Model)
27 changes: 27 additions & 0 deletions examples/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[deps]
CPLEX = "a076750e-1247-5638-91d2-ce28b192dca0"
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
EnergyCommunity = "2f2d8a28-e724-42c4-aa4e-51fe4e6b7a61"
ExportAll = "ad2082ca-a69e-11e9-38fa-e96309a31fe4"
FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
Formatting = "59287772-0a20-5a39-b81b-1366585eb4c0"
GLPK = "60bf3e95-4087-53dc-ae20-288a0d20c6a6"
TheoryOfGames = "eb50afb4-6f20-4b37-9b66-473e668300bf"
Gurobi = "2e9cd046-0924-5485-92f1-d5272153d98b"
HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b"
ImageIO = "82e4d734-157c-48bb-816b-45c225c6df19"
JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
ReferenceTests = "324d217c-45ce-50fc-942e-d289b448e8cf"
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
SankeyPlots = "8fd88ec8-d95c-41fc-b299-05f2225f2cc5"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
TickTock = "9ff05d80-102d-5586-aa04-3a8bd1a90d20"
XLSX = "fdbf4ff8-1666-58a4-91e7-1b58723a45e0"
YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6"
8 changes: 7 additions & 1 deletion examples/RunSingleModel.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Run this script from EnergyCommunity.jl root!!!
using Pkg
Pkg.activate(".") # this line requires EnergyCommunity.jl to be the current directory
Pkg.activate("examples")

using EnergyCommunity, JuMP
using HiGHS, Plots
Expand Down Expand Up @@ -45,6 +45,9 @@ save_summary(ECModel, output_file_combined)
# Plot sankey plot of CO model
plot_sankey(ECModel)

# DataFrame of the business plan
business_plan(ECModel)

# plot 20 years business plan of CO model
business_plan_plot(ECModel)

Expand All @@ -71,5 +74,8 @@ save_summary(NC_Model, output_file_isolated)
# plot Sankey plot of NC model
plot_sankey(NC_Model)

# DataFrame of the business plan of NC model
business_plan(NC_Model)

# plot business plan of NC model
business_plan_plot(NC_Model)
4 changes: 2 additions & 2 deletions examples/RunSingleModel_complete.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Run this script from EnergyCommunity.jl root!!!
# using Pkg
# Pkg.activate(".") # this line requires EnergyCommunity.jl to be the current directory
using Pkg
Pkg.activate("examples")

using EnergyCommunity, JuMP
using HiGHS, Plots
Expand Down
150 changes: 78 additions & 72 deletions src/ECModel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,7 @@ function plot_sankey(ECModel::AbstractEC;
return plot_sankey(ECModel, sank_data; label_size=label_size)
end


"""
split_financial_terms(ECModel::AbstractEC, profit_distribution)
Expand Down Expand Up @@ -842,7 +843,7 @@ function split_financial_terms(ECModel::AbstractEC, profit_distribution=nothing)
NPV=NPV,
CAPEX=CAPEX,
OPEX=OPEX,
OEM = Ann_Maintenance,
OEM=Ann_Maintenance,
REP=Ann_Replacement,
RV=Ann_Recovery,
REWARD=Ann_reward,
Expand All @@ -853,6 +854,7 @@ function split_financial_terms(ECModel::AbstractEC, profit_distribution=nothing)
)
end


"""
split_yearly_financial_terms(ECModel::AbstractEC, profit_distribution)
Expand Down Expand Up @@ -881,7 +883,6 @@ Returns
- EN_BUY: the annualized costs from energy consumption and buying
- EN_NET: the annualized net energy costs
"""

function split_yearly_financial_terms(ECModel::AbstractEC, profit_distribution=nothing)
gen_data = ECModel.gen_data

Expand All @@ -896,63 +897,61 @@ function split_yearly_financial_terms(ECModel::AbstractEC, profit_distribution=n

if isnothing(profit_distribution)
user_set = get_user_set(ECModel)

profit_distribution = JuMP.Containers.DenseAxisArray(
fill(0.0, length(user_set)),
user_set,
[
objective_value(ECModel) - sum(ECModel.results[:NPV_us]);
ECModel.results[:NPV_us][user_set].data;
],
user_set_financial,
)
end

@assert termination_status(ECModel) != MOI.OPTIMIZE_NOT_CALLED

user_set = axes(profit_distribution)[1]
ann_factor = [1. ./((1 + field(gen_data, "d_rate")).^y) for y in year_set]

# Investment costs
CAPEX = JuMP.Containers.DenseAxisArray(
[(y == 0) ? sum(Float64[get_value(ECModel.results[:CAPEX_tot_us], u)]) : 0.0
for y in year_set, u in setdiff(user_set_financial, [EC_CODE])]
, year_set, user_set_financial
[(y == 0) && (u != EC_CODE) ? sum(Float64[get_value(ECModel.results[:CAPEX_tot_us], u)]) : 0.0
for y in year_set, u in user_set_financial]
, year_set, user_set_financial
)
# Maintenance costs
Ann_Maintenance = JuMP.Containers.DenseAxisArray(
[get_value(ECModel.results[:C_OEM_tot_us], u)
for y in year_set, u in setdiff(user_set_financial, [EC_CODE])]
[(y != 0) && (u != EC_CODE) ? get_value(ECModel.results[:C_OEM_tot_us], u) : 0.0
for y in year_set, u in user_set_financial]
, year_set, user_set_financial
)
# Replacement costs
#The index is 1:20 so in the result should be proper changed. I'll open an issue
Ann_Replacement = JuMP.Containers.DenseAxisArray(
[(y == 10) ? get_value(ECModel.results[:C_REP_tot_us][y, :], u) : 0.0
for y in year_set, u in setdiff(user_set_financial, [EC_CODE])]
[(y != 0) && (u != EC_CODE) ? get_value(ECModel.results[:C_REP_tot_us][y, :], u) : 0.0
for y in year_set, u in user_set_financial]
, year_set, user_set_financial
)
# Recovery value
Ann_Recovery = JuMP.Containers.DenseAxisArray(
[(y == project_lifetime) ? (get_value(ECModel.results[:R_RV_tot_us][y, :], u)) : 0.0
for y in year_set, u in setdiff(user_set_financial, [EC_CODE])]
[(y != 0) && (u != EC_CODE) ? (get_value(ECModel.results[:R_RV_tot_us][y, :], u)) : 0.0
for y in year_set, u in user_set_financial]
, year_set, user_set_financial
)
# Peak energy charges
Ann_peak_charges = JuMP.Containers.DenseAxisArray(
[get_value(ECModel.results[:C_Peak_tot_us], u)
for y in year_set, u in setdiff(user_set_financial, [EC_CODE])]
[(y != 0) && (u != EC_CODE) ? get_value(ECModel.results[:C_Peak_tot_us], u) : 0.0
for y in year_set, u in user_set_financial]
, year_set, user_set_financial
)
# Get revenes by selling energy and costs by buying or consuming energy
Ann_energy_revenues = JuMP.Containers.DenseAxisArray(
[(u in axes(ECModel.results[:R_Energy_us])[1]) ? sum(zero_if_negative.(ECModel.results[:R_Energy_us][u,:])) : 0.0
for y in year_set, u in setdiff(user_set_financial, [EC_CODE])]
[(y != 0) && (u in axes(ECModel.results[:R_Energy_us])[1]) && (u != EC_CODE) ?
sum(zero_if_negative.(ECModel.results[:R_Energy_us][u,:])) : 0.0
for y in year_set, u in user_set_financial]
, year_set, user_set_financial
)
Ann_energy_costs = JuMP.Containers.DenseAxisArray(
[(u in axes(ECModel.results[:R_Energy_us])[1]) ? sum(zero_if_negative.(.-(ECModel.results[:R_Energy_us][u, :]))) : 0.0
for y in year_set, u in setdiff(user_set_financial, [EC_CODE])]
, year_set, user_set_financial
)

Ann_energy_reward = JuMP.Containers.DenseAxisArray(
[ECModel == ECModel ? ECModel.results[:R_Reward_agg_tot] : 0.0
for y in year_set, u in [EC_CODE]]
[(y != 0) && (u in axes(ECModel.results[:R_Energy_us])[1]) && (u != EC_CODE) ? sum(zero_if_negative.(.-(ECModel.results[:R_Energy_us][u, :]))) : 0.0
for y in year_set, u in user_set_financial]
, year_set, user_set_financial
)

Expand All @@ -963,42 +962,41 @@ function split_yearly_financial_terms(ECModel::AbstractEC, profit_distribution=n
OPEX = Ann_Maintenance .+ Ann_peak_charges .+ Ann_ene_net_costs

# get NPV given the reward allocation
#=
Basically, what we may need to do is to create a proxy total discounted cost of all terms but NPV so to reproduce the old (CAPEX .+ OPEX .+ Ann_Replacement .- Ann_Recovery).
For example, something like:
(CAPEX .+ OPEX .+ Ann_Replacement .- Ann_Recovery).data * ann_factor (note that since they are matrix operation, there may be the need for some transpositions
Then, the resulting vector shall be a 1 column or 1 vector and we can create the equivalent 1D cost vector, so that we can do (total_discounted_reward = NPV .- new_vector).
Then, we can do total_discounted_reward ./(sum(act_factor) - 1) and this should be a 1D vector of the yearly reward allocation by user, that can be exploded into 2D by simply duplicating the entries.
=#
# Using the total NPV by user, we calculate the annual reward that enables that
NPV = JuMP.Containers.DenseAxisArray(
[get_value(profit_distribution, u)
for u in setdiff(user_set_financial, [EC_CODE])]
, user_set_financial
[get_value(profit_distribution, u) for u in user_set_financial],
user_set_financial,
)

# Total reward
# This is the total discounted cost of all terms but NPV. I think that this must be improved
total_discounted_cost= CAPEX .+ OPEX .+ Ann_Replacement .- Ann_Recovery
total_discounted_cost_by_user = JuMP.Containers.DenseAxisArray(
(CAPEX .+ OPEX .+ Ann_Replacement .- Ann_Recovery).data' * ann_factor,
user_set_financial,
)
total_discounted_reward_by_user = NPV .+ total_discounted_cost_by_user

#=Ann_reward = JuMP.Containers.DenseAxisArray(
[(NPV[u] .- sum(total_discounted_cost[:,u]))/(sum(ann_factor) - 1) for y in year_set, u in setdiff(user_set_financial, [EC_CODE])]
, year_set, user_set_financial
)=#
Ann_reward = JuMP.Containers.DenseAxisArray(
[
(y != 0) ? total_discounted_reward_by_user[u]/(sum(ann_factor) - 1) : 0.0
for y in year_set, u in user_set_financial
],
year_set, user_set_financial
)

return (
NPV=NPV,
CAPEX=CAPEX,
OPEX=OPEX,
OEM = Ann_Maintenance,
REP = Ann_Replacement,
RV = Ann_Recovery,
REWARD = Ann_energy_reward,
PEAK = Ann_peak_charges,
EN_SELL = Ann_energy_revenues,
EN_CONS = Ann_energy_costs,
year_set = year_set
OEM=Ann_Maintenance,
REP=Ann_Replacement,
RV=Ann_Recovery,
REWARD=Ann_reward,
PEAK=Ann_peak_charges,
EN_SELL=Ann_energy_revenues,
EN_CONS=Ann_energy_costs,
EN_NET=Ann_ene_net_costs,
year_set=year_set,
)
end

Expand All @@ -1022,7 +1020,6 @@ Returns
- df_business
Dataframe with the business plan information
"""

function business_plan(ECModel::AbstractEC,profit_distribution=nothing, user_set_financial=nothing)
gen_data = ECModel.gen_data

Expand All @@ -1043,7 +1040,7 @@ function business_plan(ECModel::AbstractEC,profit_distribution=nothing, user_set
df_business = DataFrame(Year = Int[], CAPEX = Float64[], OEM = Float64[], EN_SELL = Float64[], EN_CONS = EN_SELL = Float64[], PEAK = Float64[], REP = Float64[],
REWARD = Float64[], RV = Float64[])
for i in year_set
Year = 0 + year_set[i+1]
Year = year_set[i+1]
CAPEX = sum(business_plan.CAPEX[i, :])
OEM = sum(business_plan.OEM[i, :])
EN_SELL = sum(business_plan.EN_SELL[i, :])
Expand Down Expand Up @@ -1076,13 +1073,12 @@ Returns
-------
The output value is a plot with the business plan information
"""

function business_plan_plot(
ECModel::AbstractEC;
plot_struct=nothing,
xlabel="Year",
ylabel="Amount [k€]",
title="Business Plan Over 20 Years",
title="Business Plan",
legend=:bottomright,
color=:auto,
xrotation=45,
Expand All @@ -1091,7 +1087,8 @@ function business_plan_plot(
framestyle=:box,
barmode=:stack,
scaling_factor = 0.001,
kwargs...)
kwargs...
)

df_business = business_plan(ECModel)

Expand All @@ -1102,29 +1099,38 @@ function business_plan_plot(
"Repl. and Recovery" => [(-1, :REP), (+1, :RV)],
"OEM" => [(-1, :OEM), (-1, :PEAK)],
"Energy expences" => [(-1, :EN_CONS), (+1, :EN_SELL)],
"Reward" => [(+1, :REWARD)])
"Reward" => [(+1, :REWARD)],
)
end

# Extract the year from the DataFrame
years = df_business.Year

bar_labels = keys(plot_struct)
bar_data = [sum(tup[1] .* df_business[!, tup[2]] .* scaling_factor for tup in plot_struct[l]) for l in keys(plot_struct)]
bar_labels = hcat(keys(plot_struct)...)
bar_data = [
sum(
tup[1] .* df_business[!, tup[2]] .* scaling_factor
for tup in plot_struct[l]
)
for l in keys(plot_struct)
]

# Create a bar plot
p = bar(years, bar_data,
labelS=bar_labels,
xlabel=xlabel, ylabel=ylabel,
title=title,
legend=legend,
color=color,
xrotation=xrotation,
bar_width=bar_width,
grid=grid,
framestyle=framestyle,
barmode=barmode,
kwargs...
)
p = bar(
years,
bar_data,
labels=bar_labels,
xlabel=xlabel, ylabel=ylabel,
title=title,
legend=legend,
color=color,
xrotation=xrotation,
bar_width=bar_width,
grid=grid,
framestyle=framestyle,
barmode=barmode,
kwargs...
)

return p
end
Expand Down

0 comments on commit 957ff03

Please sign in to comment.