Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
7 changes: 6 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Release notes

## Unversioned

### Bugfix

* Fixed a bug in the functionality `get_all_periods` when using `RepresentativePeriods` or `OperationalScenarios`.

## Version 0.7.2 (2026-08-04)

Expand Down Expand Up @@ -68,7 +73,6 @@
* Improved testing of `descriptive_names` and added more names from other packages.
* Improved documentation.


## Version 0.6.0 (2025-12-15)

### Bugfix
Expand Down Expand Up @@ -336,6 +340,7 @@
* Relaxed redundant minor version specification in the `Project.toml`-file.

### Feature

* Provided the user with the ability to provide descriptive_names in the folder `ext/EMGUIExt/descriptive_names.yml` for a EMX package, and/or
a user defined file, and/or a user defined Dict.

Expand Down
71 changes: 41 additions & 30 deletions src/utils_GUI/GUI_utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ end
pick_component!(gui::GUI, ::Nothing, ax_type::Symbol)

Check if a system is found under the mouse pointer and if it is an `AbstractGUIObj` (for
objects in the topology axis) or a `Dict` (for objects in the results axis). If found,
objects in the topology axis) or a `Dict` (for objects in the results axis). If found,
state variables are updated. Results in the topology axis are only cleared if `ax_type = :topo`
and in the results axis if `ax_type = :results`.
"""
Expand All @@ -108,7 +108,7 @@ end
"""
clear_selection!(gui::GUI, ax_type::Symbol)

Clear the color selection of the topology axis if `ax_type = :topo`, and of the results axis
Clear the color selection of the topology axis if `ax_type = :topo`, and of the results axis
if `ax_type = :results`.
"""
function clear_selection!(gui::GUI, ax_type::Symbol)
Expand Down Expand Up @@ -407,7 +407,7 @@ function initialize_available_data!(gui)
end
end

# Add additional plots provided by the user
# Add additional plots provided by the user
element = nothing # Additional plots are not associated with a specific element
for (i, additional_plot) ∈ enumerate(get_var(gui, :additional_plots))
df = get_data(additional_plot["data"])
Expand Down Expand Up @@ -599,8 +599,8 @@ get_values(vals::TimeProfile, ts::Vector) = vals[ts]
"""
get_inv_objs(obj::AbstractElement)

Get the objects for which investment information should be stored for a given `AbstractElement`.
By default, this is just the element itself, but for some elements (e.g., `Transmission`) it can
Get the objects for which investment information should be stored for a given `AbstractElement`.
By default, this is just the element itself, but for some elements (e.g., `Transmission`) it can
be relevant to also store the investment information of related objects (e.g., its modes).
"""
get_inv_objs(obj::AbstractElement) = [obj]
Expand Down Expand Up @@ -827,8 +827,8 @@ end
"""
select_data!(gui::GUI, name::String; selection::Vector = Any[], fun::Function = findfirst)

Select the data with name `name` from the `available_data` menu. If `selection` is provided,
it is used to further specify which data to select. The `fun` argument is used to specify the
Select the data with name `name` from the `available_data` menu. If `selection` is provided,
it is used to further specify which data to select. The `fun` argument is used to specify the
function for finding the data in the menu (default is `findfirst`).
"""
function select_data!(
Expand Down Expand Up @@ -880,40 +880,51 @@ Get all TimeStructures in `𝒯` as a dictionary with their string representatio
"""
function get_all_periods(𝒯::TimeStructure)
all_periods = Union{TS.TimePeriod,TS.TimeStructure}[]
get_all_periods!(all_periods, 𝒯)
get_all_periods!(all_periods, 𝒯, 𝒯)
return get_repr_dict(unique(all_periods))
end

"""
get_all_periods!(vec::Vector, ts::TwoLevel)
get_all_periods!(vec::Vector, ts::RepresentativePeriods)
get_all_periods!(vec::Vector, ts::OperationalScenarios)
get_all_periods!(vec::Vector, ts::Any)
get_all_periods!(vec::Vector, per, ::TwoLevel)
get_all_periods!(vec::Vector, per, ::RepresentativePeriods)
get_all_periods!(vec::Vector, per, ::OperationalScenarios)
get_all_periods!(vec::Vector, per, ::SimpleTimes)
get_all_periods!(::Vector, per, ::Any)

Get all TimeStructures in `ts` and append them to `vec`.
Get all `TimeStructure`s in `per` and append them to `vec`. The required time structures
are automatically deduced from the internal structure of `per`.
"""
function get_all_periods!(vec::Vector, ts::TwoLevel)
append!(vec, collect(ts))
append!(vec, strategic_periods(ts))
for t ∈ ts.operational
get_all_periods!(vec, t)
function get_all_periods!(vec::Vector, per, ::TwoLevel)
Comment thread
dqpinel marked this conversation as resolved.
𝒯ᴵⁿᵛ = strategic_periods(per)
append!(vec, 𝒯ᴵⁿᵛ)
for t_inv ∈ 𝒯ᴵⁿᵛ
get_all_periods!(vec, t_inv, t_inv.operational)
end
end
function get_all_periods!(vec::Vector, ts::RepresentativePeriods)
append!(vec, repr_periods(ts))
for t ∈ ts.rep_periods
get_all_periods!(vec, t)
function get_all_periods!(vec::Vector, per, ::RepresentativePeriods)
𝒯ʳᵖ = repr_periods(per)
append!(vec, 𝒯ʳᵖ)
for t_rp ∈ 𝒯ʳᵖ
ts =
isa(per, TS.TimeStructurePeriod) ? t_rp.operational.operational :
t_rp.operational
get_all_periods!(vec, t_rp, ts)
end
end
function get_all_periods!(vec::Vector, ts::OperationalScenarios)
append!(vec, opscenarios(ts))
for t ∈ ts.scenarios
get_all_periods!(vec, t)
function get_all_periods!(vec::Vector, per, ::OperationalScenarios)
𝒯ˢᶜ = opscenarios(per)
append!(vec, 𝒯ˢᶜ)
for t_scp ∈ 𝒯ˢᶜ
ts =
isa(per, TS.TimeStructurePeriod) ? t_scp.operational.operational :
t_scp.operational
get_all_periods!(vec, t_scp, ts)
end
end
function get_all_periods!(::Vector, ::Any)
return nothing
function get_all_periods!(vec::Vector, per, ::SimpleTimes)
append!(vec, collect(per))
end
get_all_periods!(::Vector, per, ::Any) = nothing

"""
get_repr_dict(vec::AbstractVector{T}) where T
Expand Down Expand Up @@ -981,7 +992,7 @@ end
"""
read_csv(file::String)

Read a CSV file and return it as a DataFrame. The time column is renamed to :t if it is
Read a CSV file and return it as a DataFrame. The time column is renamed to :t if it is
named "t", "sp", "rp", "osc", or "op".
"""
function read_csv(file::String)
Expand All @@ -993,7 +1004,7 @@ end
"""
rename_time_column!(df::DataFrame)

Rename the time column in `df` to :t if it is named "t", "sp", "rp", "osc", or "op".
Rename the time column in `df` to :t if it is named "t", "sp", "rp", "osc", or "op".
If more than one of these columns are present, an error is thrown.
"""
function rename_time_column!(df::DataFrame)
Expand Down
7 changes: 5 additions & 2 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ global_logger(logger_new)
# Check if there is need for formatting
include(joinpath(testdir, "JuliaFormatter.jl"))

# The following tests simply checks if the main examples can be run without errors
include(joinpath(testdir, "test_examples.jl"))
# Test some of the utility functionality
include(joinpath(testdir, "test_utils.jl"))

# The following tests results input and output functionality (saving and loading results)
include(joinpath(testdir, "test_results_IO.jl"))
Expand All @@ -54,6 +54,9 @@ global_logger(logger_new)

# Test descriptive names functionalities
include(joinpath(testdir, "test_descriptive_names.jl"))

# The following tests simply checks if the main examples can be run without errors
include(joinpath(testdir, "test_examples.jl"))
end
end
global_logger(logger_org)
67 changes: 67 additions & 0 deletions test/test_utils.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
@testset "CSV utilities" begin
# Simplified function for testing
function test_pers(opers, pers_dict)
@test isempty(setdiff(repr.(opers), keys(pers_dict)))
@test isempty(setdiff(opers, values(pers_dict)))
end

# Test for SimpleTimes
ts_opers = SimpleTimes(4, 1)
pers_dict = EMGUI.get_all_periods(ts_opers)
test_pers(collect(ts_opers), pers_dict)
@test length(pers_dict) == 4

# Test for OperationalScenarios
ts_oscs = OperationalScenarios(2, ts_opers)
pers_dict = EMGUI.get_all_periods(ts_oscs)
test_pers(collect(ts_oscs), pers_dict)
test_pers(opscenarios(ts_oscs), pers_dict)
@test length(pers_dict) == (4 + 1) * 2

# Test for RepresentativePeriods{SimpleTimes}
ts_rp = RepresentativePeriods(2, 8760, ts_opers)
pers_dict = EMGUI.get_all_periods(ts_rp)
test_pers(collect(ts_rp), pers_dict)
test_pers(repr_periods(ts_rp), pers_dict)
@test length(pers_dict) == (4 + 1) * 2

# Test for RepresentativePeriods{OperationalScenarios}
ts_rp_oscs = RepresentativePeriods(2, 8760, ts_oscs)
pers_dict = EMGUI.get_all_periods(ts_rp_oscs)
test_pers(collect(ts_rp_oscs), pers_dict)
test_pers(opscenarios(ts_rp_oscs), pers_dict)
test_pers(repr_periods(ts_rp_oscs), pers_dict)
@test length(pers_dict) == ((4 + 1) * 2 + 1) * 2

# Test for TwoLevel{SimpleTimes}
ts_tl = TwoLevel(2, 1, ts_opers)
pers_dict = EMGUI.get_all_periods(ts_tl)
test_pers(collect(ts_tl), pers_dict)
test_pers(strat_periods(ts_tl), pers_dict)
@test length(pers_dict) == (4 + 1) * 2

# Test for TwoLevel{OperationalScenarios}
ts_tl_oscs = TwoLevel(2, 1, ts_oscs)
pers_dict = EMGUI.get_all_periods(ts_tl_oscs)
test_pers(collect(ts_tl_oscs), pers_dict)
test_pers(opscenarios(ts_tl_oscs), pers_dict)
test_pers(strat_periods(ts_tl_oscs), pers_dict)
@test length(pers_dict) == ((4 + 1) * 2 + 1) * 2

# Test for TwoLevel{RepresentativePeriods}
ts_tl_rp = TwoLevel(2, 1, ts_rp)
pers_dict = EMGUI.get_all_periods(ts_tl_rp)
test_pers(collect(ts_tl_rp), pers_dict)
test_pers(repr_periods(ts_tl_rp), pers_dict)
test_pers(strat_periods(ts_tl_rp), pers_dict)
@test length(pers_dict) == ((4 + 1) * 2 + 1) * 2

# Test for TwoLevel{RepresentativePeriods{OperationalScenarios}}
ts_tl_rp_oscs = TwoLevel(2, 1, ts_rp_oscs)
pers_dict = EMGUI.get_all_periods(ts_tl_rp_oscs)
test_pers(collect(ts_tl_rp_oscs), pers_dict)
test_pers(opscenarios(ts_tl_rp_oscs), pers_dict)
test_pers(repr_periods(ts_tl_rp_oscs), pers_dict)
test_pers(strat_periods(ts_tl_rp_oscs), pers_dict)
@test length(pers_dict) == (((4 + 1) * 2 + 1) * 2 + 1) * 2
end
Loading