diff --git a/src/call_plots.jl b/src/call_plots.jl index ace2451..d9b2719 100644 --- a/src/call_plots.jl +++ b/src/call_plots.jl @@ -158,7 +158,11 @@ plot = plot_demand(res) - `title::String`: Set a title for the plots - `horizon::Int64`: To plot a shorter window of time than the full results - `initial_time::DateTime`: To start the plot at a different time other than the results initial time -- `aggregate::String = "System", "PowerLoad", or "Bus"`: aggregate the demand other than by generator +- `aggregation::Type = PowerSystems.StaticLoad`: aggregate the demand by + [`PowerSystems.System`](@extref), [`PowerSystems.ACBus`](@extref), a `PowerSystems.StaticLoad` + subtype such as [`PowerSystems.PowerLoad`](@extref), or a `PowerSystems.AggregationTopology` + subtype. Only applies when plotting a [`PowerSystems.System`](@extref). +- `aggregate::String`: convenience alias for `aggregation`: `"System"`, `"Bus"`, or `"PowerLoad"` - `set_display::Bool = true`: set to false to prevent the plots from displaying - `save::String = "file_path"`: set a file path to save the plots - `format::String = "png"`: file extension for saved plots. CairoMakie supports `"png"`, `"pdf"`, `"svg"`. PlotlyLight only supports `"html"` (other values are written as `.html` with a warning). @@ -271,9 +275,11 @@ instead of CairoMakie. - `title::String`: Set a title for the plots - `horizon::Int64`: To plot a shorter window of time than the full results - `initial_time::DateTime`: To start the plot at a different time other than the results initial time -- `aggregate::String = "System", "PowerLoad", or "Bus"`: aggregate the demand by - [`PowerSystems.System`](@extref), [`PowerSystems.PowerLoad`](@extref), or [`PowerSystems.Bus`](@extref), - rather than by generator +- `aggregation::Type = PowerSystems.StaticLoad`: aggregate the demand by + [`PowerSystems.System`](@extref), [`PowerSystems.ACBus`](@extref), a `PowerSystems.StaticLoad` + subtype such as [`PowerSystems.PowerLoad`](@extref), or a `PowerSystems.AggregationTopology` + subtype. Only applies when plotting a [`PowerSystems.System`](@extref). +- `aggregate::String`: convenience alias for `aggregation`: `"System"`, `"Bus"`, or `"PowerLoad"` - `set_display::Bool = true`: set to false to prevent the plots from displaying - `save::String = "file_path"`: set a file path to save the plots - `format::String = "png"`: file extension for saved plots. CairoMakie supports `"png"`, `"pdf"`, `"svg"`. PlotlyLight only supports `"html"` (other values are written as `.html` with a warning). diff --git a/test/test_demand_aggregation.jl b/test/test_demand_aggregation.jl new file mode 100644 index 0000000..e5c56b1 --- /dev/null +++ b/test/test_demand_aggregation.jl @@ -0,0 +1,35 @@ +@testset "demand aggregation keyword" begin + for (str, type) in + ("System" => PSY.System, "Bus" => PSY.ACBus, "PowerLoad" => PSY.PowerLoad) + translated = PG._translate_demand_aggregate(Dict(:aggregate => str)) + @test translated[:aggregation] === type + @test !haskey(translated, :aggregate) + end + + # Issue #126: a typed `aggregation` passed directly must reach PowerAnalytics untouched, + # without disturbing the other keywords. + passthrough = + PG._translate_demand_aggregate(Dict(:aggregation => PSY.ACBus, :title => "demand")) + @test passthrough[:aggregation] === PSY.ACBus + @test passthrough[:title] == "demand" + + # A type given under the legacy `aggregate` name is forwarded, not stringified. + @test PG._translate_demand_aggregate(Dict(:aggregate => PSY.ACBus))[:aggregation] === + PSY.ACBus + + # `aggregate = nothing` means "no aggregation": PowerAnalytics keeps its own default. + @test !haskey(PG._translate_demand_aggregate(Dict(:aggregate => nothing)), :aggregation) + + @test_throws ArgumentError PG._translate_demand_aggregate(Dict(:aggregate => "bus")) + + # `PA.get_load_data(::PSY.System)` only aggregates over `PSY.System`, `PSY.ACBus`, + # `StaticLoad` subtypes and `AggregationTopology` subtypes, so every type the table + # maps to has to fall in that set. "System" and "Bus" are also covered end to end in + # test_plot_creation.jl; this catches "PowerLoad" and any entry added later. + @test all( + t -> + t in (PSY.System, PSY.ACBus) || + t <: Union{PSY.StaticLoad, PSY.AggregationTopology}, + values(PG._AGGREGATE_STRING_TO_TYPE), + ) +end diff --git a/test/test_plot_creation.jl b/test/test_plot_creation.jl index 69cf878..23a8b1f 100644 --- a/test/test_plot_creation.jl +++ b/test/test_plot_creation.jl @@ -267,6 +267,17 @@ function test_plots(file_path::String; backend_pkg::String = "cairomakie") plot_length = backend_pkg == "cairomakie" ? p.series_count : length(p.data) @test plot_length == 3 + # Issue #126: the typed `aggregation` keyword must survive to `get_load_data`. + # Not saved, so the expected file list below is unchanged. + p = plot_demand_fn( + sys_with_ts; + set_display = set_display, + title = "sysdemand_aggregation", + aggregation = ACBus, + ) + plot_length = backend_pkg == "cairomakie" ? p.series_count : length(p.data) + @test plot_length == 3 + list = readdir(out_path) # PlotlyLight only supports HTML export, CairoMakie supports PNG file_ext = backend_pkg == "plotlylight" ? ".html" : ".png"