Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Release notes

## Version 0.5.13 (2025-06-02)

### Bugfix

* Fix bug when `length(get_products(system)) == length(id_to_color_map)` but when `get_products(system)` is not a subset of `keys(id_to_color_map)`. This case did not expand `id_to_color_map` correctly.
* Add missing description of the `case_name` option in the `GUI`-function.
* Add the `EnergyModelsGUI` package in the `Project.toml` file in the examples folder.

### Enhancement

* Added more descriptive names for `EnergyModelsHeat` and `EnergyModelsHydrogen` and add a colors for the `HeatLT` and `HeatHT` resources.

### Adjustment
* Order the colors (by id) in the Resources legend.
* Move boundaries for countries just above the ocean layer.
* Fix default placements of the nodes in a uniform circle (when coordinates are not provided).
* Only create the design-folder if needed.

## Version 0.5.12 (2025-03-09)

### Enhancement
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "EnergyModelsGUI"
uuid = "737a7361-d3b7-40e9-b1ac-59bee4c5ea2d"
authors = ["Jon Vegard Venås <JonVegard.Venas@sintef.no>", "Magnus Askeland <Magnus.Askeland@sintef.no>", "Shweta Tiwari <Shweta.Tiwari@sintef.no>"]
version = "0.5.12"
version = "0.5.13"

[deps]
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
Expand Down
1 change: 1 addition & 0 deletions examples/Project.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[deps]
EnergyModelsBase = "5d7e687e-f956-46f3-9045-6f5a5fd49f50"
EnergyModelsGUI = "737a7361-d3b7-40e9-b1ac-59bee4c5ea2d"
EnergyModelsGeography = "3f775d88-a4da-46c4-a2cc-aa9f16db6708"
EnergyModelsInvestments = "fca3f8eb-b383-437d-8e7b-aac76bb2004f"
EnergyModelsRenewableProducers = "b007c34f-ba52-4995-ba37-fffe79fbde35"
Expand Down
4 changes: 3 additions & 1 deletion src/colors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ ResourceEmit: "#606060" # gray
CO2: "#606060" # gray
CO₂: "#606060" # gray
Coal: "#6D392E" # brown
Water: "#bfefff" # sky blue
Water: "#bfefff" # sky blue
HeatLT: "#fbdfb0" # :navajowhite
HeatHT: "#e78582" # :lightcoral
152 changes: 152 additions & 0 deletions src/descriptive_names.yml
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,146 @@ structures:
reserve_down: "Resources used as reserve for removing capacity"
data: "Additional data"

CycleLife:
stack_cost: "Relative cost for replacing a battery stack"

## EnergyModelsHeat
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No ThermalEnergyStorage? Probably ok with the base as the other parameters are no TimeProfiles

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will add ThermalEnergyStorage.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please just check that it is necessary. Based on my understanding, it should not be.

HeatPump:
cap: "Installed capacity"
t_source: "Heat source temperature"
t_sink: "Heat sink temperature"
eff_carnot: "Carnot Efficiency"
opex_var: "Variable operating expense per energy unit produced"
opex_fixed: "Fixed operating expense per installed capacity"
ResourceHeat:
t_supply: "Supply temperature in °C"
t_return: "Return temperature in °C"
DHPipe:
cap: "Heat transport capacity of the pipe"
t_ground: "Ground temperature in °C"
HeatExchanger:
cap: "Installed capacity"
opex_var: "Variable operating expense per energy unit produced"
opex_fixed: "Fixed operating expense per installed capacity"
DirectHeatUpgrade:
cap: "Installed capacity"
opex_var: "Variable operating expense per energy unit produced"
opex_fixed: "Fixed operating expense per installed capacity"

## EnergyModelsHydrogen
LoadLimits:
min: "Minimum load as a fraction of installed capacity"
max: "Maximum load as a fraction of installed capacity"

Electrolyzer:
cap: "Installed capacity"
opex_var: "Variable operating expense per capacity used"
opex_fixed: "Fixed operating expense per installed capacity"
input: "Input resources with conversion values"
output: "Produced resources with conversion values"
data: "Additional data (e.g., for investments)"
load_limits: "Limits on utilization load"
degradation_rate: "Efficiency degradation rate in % per 1000 operational hours"
stack_replacement_cost: "Replacement cost of electrolyzer stacks"
stack_lifetime: "Total operational stack lifetime in hours"

SimpleElectrolyzer:
cap: "Installed capacity"
opex_var: "Variable operating expense per capacity used"
opex_fixed: "Fixed operating expense per installed capacity"
input: "Input resources with conversion values"
output: "Produced resources with conversion values"
data: "Additional data (e.g., for investments)"
load_limits: "Limits on utilization load"
degradation_rate: "Efficiency degradation rate in % per 1000 operational hours"
stack_replacement_cost: "Replacement cost of electrolyzer stacks"
stack_lifetime: "Total operational stack lifetime in hours"

CommitParameters:
opex: "Operating cost per installed capacity and operational duration"
time: "Minimum time node must remain in a state before transitioning"

RampBi:
up: "Maximum positive rate of change of a node"
down: "Maximum negative rate of change of a node"

RampUp:
up: "Maximum positive rate of change of a node"

RampDown:
down: "Maximum negative rate of change of a node"

Reformer:
cap: "Installed capacity"
opex_var: "Variable operating expense per capacity usage"
opex_fixed: "Fixed operating expense per installed capacity"
input: "Input resources with conversion values"
output: "Produced resources with conversion values"
data: "Additional data (e.g., for investments)"
load_limits: "Limits on utilization load"
startup: "Parameters for startup state constraints"
shutdown: "Parameters for shutdown state constraints"
offline: "Parameters for offline state constraints"
ramp_limit: "Limit on the allowable change in capacity usage"

SimpleHydrogenStorage:
cap: "Installed storage capacity"
charge: "Charging parameters including OPEX, fixed cost, and capacity"
level: "Storage level parameters including OPEX and fixed cost"
stor_res: "Stored hydrogen resource"
input: "Input resources with conversion values"
output: "Generated resources with conversion values"
data: "Additional data (e.g., for investments)"
discharge_charge: "Maximum discharge rate relative to charge rate"
level_charge: "Storage level capacity relative to charge capacity"

HydrogenStorage:
cap: "Installed storage capacity"
charge: "Charging parameters including OPEX, fixed cost, and capacity"
stor_res: "Stored hydrogen resource"
el_res: "Electricity resource for compression"
data: "Additional data (e.g., for investments)"
discharge_charge: "Maximum discharge rate relative to charge rate"
level_charge: "Storage level capacity relative to charge capacity"
p_min: "Minimum pressure in the storage"
p_charge: "Charging pressure into the storage"
p_max: "Maximum pressure in the storage"

## EnergyModelsCO2
CO2Source:
cap: "Installed capacity"
opex_var: "Variable operating expense per energy unit produced"
opex_fixed: "Fixed operating expense"
output: "Generated resources with conversion values"
data: "Additional data (e.g., for investments)"

CO2Storage:
cap: "Installed injection rate capacity"
charge: "Charging parameters (OPEX, fixed cost)"
level: "Storage capacity parameters (OPEX, fixed cost)"
stor_res: "Stored resource type (CO₂)"
input: "Input resources with conversion values"
data: "Additional data (e.g., for investments)"

RefNetworkNodeRetrofit:
cap: "Installed capacity"
opex_var: "Variable operating expense per energy unit produced"
opex_fixed: "Fixed operating expense"
input: "Input resources with conversion values"
output: "Generated resources with conversion values"
co2_proxy: "Instance of the CO₂ proxy resource used for capture calculations"
data: "Additional data (e.g., for investments)"

CCSRetroFit:
cap: "Installed capacity"
opex_var: "Variable operating expense per unit of CO₂ captured"
opex_fixed: "Fixed operating expense"
input: "Input resources with conversion values"
output: "Generated resources with conversion values"
co2_proxy: "Instance of the CO₂ proxy resource used for capture calculations"
data: "Additional data (e.g., for investments)"


variables:
## EnergyModelsBase
cap_use: "Absolute capacity utilization"
Expand Down Expand Up @@ -333,6 +473,18 @@ variables:
bat_res_up: "Upwards reserve of battery storage"
bat_res_down: "Downwards reserve of battery storage"

## EnergyModelsHeat
dh_pipe_loss: "Heat losses in DH pipes"

## EnergyModelsHydrogen
ref_off_b: "Binary variable indicating if the reformer is in the 'off' state in operational period t"
ref_start_b: "Binary variable indicating if the reformer is in the 'start-up' state in operational period t"
ref_on_b: "Binary variable indicating if the reformer is in the 'on' state in operational period t"
ref_shut_b: "Binary variable indicating if the reformer is in the 'shutdown' state in operational period t"

## EnergyModelsCO2
stor_level_Δ_sp: "Increase in `stor_level` during a strategic period"

# Overview of total quantities and their components
total:
opex_fields:
Expand Down
20 changes: 16 additions & 4 deletions src/setup_GUI.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ data stored as key-value pairs. This dictionary is corresponding to the the old
main window.
- **`fontsize::Int64=12`** is the general fontsize.
- **`plot_widths::Tuple{Int64,Int64}=(1920, 1080)`** is the resolution of the window.
- **`case_name::String = ""`** provides a tag for the window title.
- **`scale_tot_opex::Bool=false`** multiplies total OPEX quantities with the duration of the strategic period.
- **`scale_tot_capex::Bool=false`** divides total CAPEX quantities with the duration of the strategic period.
- **`colormap::Vector=Makie.wong_colors()`** is the colormap used for plotting results.
Expand Down Expand Up @@ -292,7 +293,7 @@ function create_makie_objects(vars::Dict, design::EnergySystemDesign)
# Create GeoMakie plotable object
countries = GeoMakie.to_multipoly(countries_geo_json.geometry)
end
poly!(
countries_plot = poly!(
ax,
countries;
color = :honeydew,
Expand All @@ -301,6 +302,7 @@ function create_makie_objects(vars::Dict, design::EnergySystemDesign)
strokewidth = 0.5,
inspectable = false,
)
Makie.translate!(countries_plot, 0, 0, -1)
ocean_coords = [(180, -90), (-180, -90), (-180, 90), (180, 90)]
ocean = poly!(
ax,
Expand All @@ -310,7 +312,7 @@ function create_makie_objects(vars::Dict, design::EnergySystemDesign)
strokecolor = :gray50,
inspectable = false,
)
Makie.translate!(ocean, 0, 0, -1)
Makie.translate!(ocean, 0, 0, -2)
else # The design does not use the EnergyModelsGeography package: Create a simple Makie axis
ax = Axis(
gridlayout_topology_ax[1, 1];
Expand Down Expand Up @@ -362,16 +364,26 @@ function create_makie_objects(vars::Dict, design::EnergySystemDesign)

# Create legend to explain the available resources in the design model
markers::Vector{Makie.Scatter} = Vector{Makie.Scatter}(undef, 0)
for color ∈ collect(values(design.id_to_color_map))

# Create an ordered list of colors (based on their id)
color_mat =
hcat(collect(keys(design.id_to_color_map)), collect(values(design.id_to_color_map)))
perm = sortperm(lowercase.(color_mat[:, 1]))
sorted_color_mat = color_mat[perm, :]

# Create markers for colors in legend
for color ∈ sorted_color_mat[:, 2]
push!(
markers,
scatter!(ax, Point2f((0, 0)); marker = :rect, color = color, visible = false),
) # add invisible dummy markers to be put in the legend box
end

# Add the legend to the axis
topo_legend = axislegend(
ax,
markers,
collect(keys(design.id_to_color_map)),
sorted_color_mat[:, 1],
"Resources";
position = :rt,
labelsize = vars[:fontsize],
Expand Down
3 changes: 1 addition & 2 deletions src/setup_topology.jl
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function EnergySystemDesign(

# Complete the `id_to_color_map` if some products are lacking (this is done by choosing
# colors for the lacking `Resource`s that are most distinct to the existing set of colors)
if !(length(get_products(system)) == length(id_to_color_map))
if !issubset(get_products(system), keys(id_to_color_map))
id_to_color_map = set_colors(get_products(system), id_to_color_map)
end

Expand Down Expand Up @@ -87,7 +87,6 @@ function EnergySystemDesign(
if element == get_ref_element(system)
x = parent_x
y = parent_y
nodes_count -= 1
else # place nodes in a circle around the parents availability node
x, y = place_nodes_in_circle(
nodes_count, current_node, 1, parent_x, parent_y,
Expand Down
9 changes: 5 additions & 4 deletions src/utils_gen/structures_utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,6 @@ function design_file(system::AbstractSystem, path::String)
if isempty(path)
return ""
end
if !isdir(path)
mkpath(path)
end
return joinpath(path, "$(get_parent(system)).yml")
end

Expand Down Expand Up @@ -233,6 +230,10 @@ Save the x,y-coordinates of `design_dict` to a .yml file at location and filenam
`file`.
"""
function save_design(design_dict::Dict, file::String)
design_dir = dirname(file)
if !isdir(design_dir)
mkpath(design_dir)
end
return YAML.write_file(file, design_dict)
end

Expand All @@ -242,7 +243,7 @@ end
links::Vector{Link},
area_links::Vector{Link},
area_nodes::Vector{EMB.Node},
indices::Vector{Int
indices::Vector{Int},
)

Recursively find all nodes connected (directly or indirectly) to `node` in a system of `links`
Expand Down
Loading