diff --git a/Project.toml b/Project.toml index 0337056..c52cdf1 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "FullNetworkSystems" uuid = "877b7152-b508-43dc-81fb-72341a693988" authors = ["Invenia Technical Computing Corporation"] -version = "1.0.0" +version = "1.1.0" [deps] AxisKeys = "94b1ba4f-4ee9-5380-92f1-94cde586c3c5" diff --git a/src/FullNetworkSystems.jl b/src/FullNetworkSystems.jl index 7db6e38..c3e57ab 100644 --- a/src/FullNetworkSystems.jl +++ b/src/FullNetworkSystems.jl @@ -10,7 +10,7 @@ export System, SystemDA, SystemRT export Zone, Generator, Bus, Branch export GeneratorTimeSeries, GeneratorStatus, GeneratorStatusDA, GeneratorStatusRT export gens_per_zone, branches_by_breakpoints, get_datetimes -export get_zones, get_buses, get_generators, get_branches +export get_zones, get_buses, get_generators, get_branches, get_lines, get_transformers export get_regulation_requirements, get_operating_reserve_requirements, get_good_utility_requirements export get_gens_per_bus, get_loads_per_bus, get_incs_per_bus, get_decs_per_bus, get_psds_per_bus export get_ptdf, get_lodf diff --git a/src/accessors.jl b/src/accessors.jl index 9f6d0fa..45c57fb 100644 --- a/src/accessors.jl +++ b/src/accessors.jl @@ -37,6 +37,10 @@ get_buses(system::System) = system.buses get_generators(system::System) = system.generators "Returns a `Dictionary` of `Branch` objects in the `System` indexed by branch name." get_branches(system::System) = system.branches +"Returns a `Dictionary` of branches that are not transformers in the `System` indexed by name." +get_lines(system::System) = filter(br -> !br.is_transformer, system.branches) +"Returns a `Dictionary` of transformers in the `System` indexed by name." +get_transformers(system::System) = filter(br -> br.is_transformer, system.branches) "Returns a `Dictionary` of unit codes at each bus." get_gens_per_bus(system::System) = system.gens_per_bus diff --git a/src/system.jl b/src/system.jl index d57b9c5..fab9296 100644 --- a/src/system.jl +++ b/src/system.jl @@ -73,8 +73,8 @@ end """ $TYPEDEF -Type for static branch attributes. Branches may have between 0 and 2 break points -which is why the `break_points` and `penalties` fields contain variable length `Tuple`s. +Type for static branch attributes. Branches may have between 0 and 2 break +points which is why the `break_points` and `penalties` fields contain variable length `Tuple`s. Fields: $TYPEDFIELDS @@ -86,9 +86,9 @@ struct Branch to_bus::BusName "Name of the bus the branch goes from" from_bus::BusName - "Power flow limit for the base case (MVA)" + "Power flow limit for the base case (pu)" rate_a::Float64 - "Power flow limit for contingency scenario (MVA)" + "Power flow limit for contingency scenario (pu)" rate_b::Float64 "Boolean defining whether the branch is monitored" is_monitored::Bool @@ -99,6 +99,94 @@ struct Branch break_points::Tuple{Float64, Float64} "Price penalties for each of the break points of the branch (\$)" penalties::Tuple{Float64, Float64} + "Resistance of the branch (pu)" + resistance::Float64 + "Reactance of the branch (pu)" + reactance::Float64 + "Boolean indicating whether the branch is a transformer" + is_transformer::Bool + "Ratio between the nominal winding one and two voltages of the transformer" + tap::Union{Missing, Float64} + "Phase shift angle (radians)" + angle::Union{Missing, Float64} +end + +""" +Constructors for a `Branch`. The user has the option to define a `Branch` as a line e.g. +``` +line1 = Branch("1", "A", "B", 10.0, 10.0, true, (100.0, 102.0), (5.0, 6.0), 1.0, 1.0) +``` +where the final two values (`resistance` and `reactance`) can be left unspecified. Or the +user can define a `Branch`` as a transformer: +``` +trnasformer1 = Branch( + "4", "A", "C", 10.0, 10.0, true, (100.0, 102.0), (5.0, 6.0), 1.0, 1.0, 0.5, 30.0 +) +``` +where two extra parameters are provided as the end representing `tap` and `angle`. +""" +function Branch( + name, + to_bus, + from_bus, + rate_a, + rate_b, + is_monitored, + break_points, + penalities, + resistance=0.0, + reactance=0.0 +) + tap = missing + angle = missing + is_transformer = false + return Branch( + name, + to_bus, + from_bus, + rate_a, + rate_b, + is_monitored, + break_points, + penalities, + resistance, + reactance, + is_transformer, + tap, + angle + ) +end + +function Branch( + name, + to_bus, + from_bus, + rate_a, + rate_b, + is_monitored, + break_points, + penalities, + resistance, + reactance, + tap::Float64, + angle::Float64 +) + is_transformer = true + return Branch( + name, + to_bus, + from_bus, + rate_a, + rate_b, + is_monitored, + break_points, + penalities, + resistance, + reactance, + is_transformer, + tap, + angle + ) end ###### Time Series types ###### diff --git a/test/system.jl b/test/system.jl index 22bdf64..b1f503b 100644 --- a/test/system.jl +++ b/test/system.jl @@ -14,9 +14,6 @@ ids=gen_ids, datetimes=datetimes ) - branch_names = string.([1, 2, 3]) - bus_names = ["A", "B", "C"] - @testset "Zone" begin zone1 = Zone(1, 1.0, 1.0, 1.0) @test zone1 isa Zone @@ -33,8 +30,18 @@ end @testset "Branch" begin - branch1 = Branch("1", "A", "C", 10.0, 10.0, true, (100.0, 102.0), (5.0, 6.0)) + branch1 = Branch("1", "A", "C", 10.0, 10.0, true, (100.0, 102.0), (5.0, 6.0), 1.0, 1.0) @test branch1 isa Branch + @test !branch1.is_transformer + + branch2 = Branch("2", "A", "C", 10.0, 10.0, true, (100.0, 102.0), (5.0, 6.0)) + @test branch2 isa Branch + @test !branch2.is_transformer + + transformer1 = Branch( + "1", "A", "C", 10.0, 10.0, true, (100.0, 102.0), (5.0, 6.0), 1.0, 1.0, 0.5, 30.0 + ) + @test transformer1 isa Branch end @testset "System" begin @@ -48,17 +55,22 @@ end gens = Dictionary(gen_ids, gen_types) + bus_names = ["A", "B", "C"] bus_types = map(bus_names) do name Bus(name, 100.0) end buses = Dictionary(bus_names, bus_types) + branch_names = string.([1,2,3,4]) branches = Dictionary( branch_names, [ - Branch("1", "A", "B", 10.0, 10.0, true, (100.0, 102.0), (5.0, 6.0)), - Branch("2", "B", "C", 10.0, 10.0, false, (100.0, 0.0), (5.0, 0.0)), - Branch("3", "C", "A", 10.0, 10.0, true, (0.0, 0.0), (0.0, 0.0)), + Branch("1", "A", "B", 10.0, 10.0, true, (100.0, 102.0), (5.0, 6.0), 1.0, 1.0), + Branch("2", "B", "C", 10.0, 10.0, false, (100.0, 0.0), (5.0, 0.0), 1.0, 1.0), + Branch("3", "C", "A", 10.0, 10.0, true, (0.0, 0.0), (0.0, 0.0), 1.0, 1.0), + Branch( + "4", "A", "C", 10.0, 10.0, true, (100.0, 102.0), (5.0, 6.0), 1.0, 1.0, 0.5, 30.0 + ) ] ) @@ -70,9 +82,9 @@ lodf = Dictionary( ["CONTIN_1"], - [KeyedArray(rand(3, 1); branches=branch_names, branch=[first(branch_names)])] + [KeyedArray(rand(4, 1); branches=branch_names, branch=[first(branch_names)])] ) - ptdf = KeyedArray(rand(3, 3); row=branch_names, col=bus_names) + ptdf = KeyedArray(rand(4, 3); row=branch_names, col=bus_names) generator_time_series = GeneratorTimeSeries( fake_vec_ts, @@ -136,6 +148,10 @@ @test get_buses(system) == buses @test get_generators(system) == gens @test get_branches(system) == branches + @test get_lines(system) == Dictionary( + ["1", "2", "3"], [branches["1"], branches["2"], branches["3"]] + ) + @test get_transformers(system) == Dictionary(["4"], [branches["4"]]) @test get_gens_per_bus(system) == gens_per_bus @test get_loads_per_bus(system) == loads_per_bus @@ -165,7 +181,7 @@ zero_bp, one_bp, two_bp = branches_by_breakpoints(da_system) @test zero_bp == ["3"] @test one_bp == String[] #unmonitored - @test two_bp == ["1"] + @test two_bp == ["1", "4"] end @testset "SystemDA only accessors" begin