diff --git a/README.md b/README.md index 759eefa7ee..522103bd85 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,6 @@ The `PowerSystems.jl` package provides a rigorous data model using Julia structu ## Version Advisory - PowerSystems will work with Julia v1.6+. -- If you are planning to use `PowerSystems.jl` in your package, check the [roadmap to version 4.0](https://github.com/NREL-Sienna/PowerSystems.jl/projects/4) for upcoming changes ## Device data enabled in PowerSystems diff --git a/src/base.jl b/src/base.jl index c0b07f77da..335f34a1ea 100644 --- a/src/base.jl +++ b/src/base.jl @@ -10,7 +10,7 @@ const SYSTEM_KWARGS = Set(( :generator_mapping, :internal, :load_name_formatter, - :load_zone_formatter, + :loadzone_name_formatter, :runchecks, :shunt_name_formatter, :time_series_directory, @@ -2449,6 +2449,7 @@ function convert_component!( (from_to = line.rating, to_from = line.rating), line.rating, line.angle_limits, + line.g, line.services, line.ext, _copy_internal_for_conversion(line), @@ -2492,6 +2493,7 @@ function convert_component!( line.b, line.rating, line.angle_limits, + line.g, line.services, line.ext, _copy_internal_for_conversion(line), diff --git a/src/descriptors/power_system_structs.json b/src/descriptors/power_system_structs.json index b96ba69642..3b17602928 100644 --- a/src/descriptors/power_system_structs.json +++ b/src/descriptors/power_system_structs.json @@ -480,6 +480,18 @@ }, "validation_action": "error" }, + { + "name": "g", + "null_value": "(from=0.0, to=0.0)", + "data_type": "FromTo", + "comment": "Shunt conductance in pu ([`SYSTEM_BASE`](@ref per_unit)), specified both on the `from` and `to` ends of the line. These are commonly modeled with the same value", + "valid_range": { + "min": 0, + "max": 100 + }, + "validation_action": "warn", + "default": "(from=0.0, to=0.0)" + }, { "name": "services", "data_type": "Vector{Service}", @@ -599,6 +611,18 @@ }, "validation_action": "error" }, + { + "name": "g", + "null_value": "(from=0.0, to=0.0)", + "data_type": "FromTo", + "comment": "Shunt conductance in pu ([`SYSTEM_BASE`](@ref per_unit)), specified both on the `from` and `to` ends of the line. These are commonly modeled with the same value", + "valid_range": { + "min": 0, + "max": 100 + }, + "validation_action": "warn", + "default": "(from=0.0, to=0.0)" + }, { "name": "services", "data_type": "Vector{Service}", diff --git a/src/models/generated/Line.jl b/src/models/generated/Line.jl index 2a638e096d..ffd7d58319 100644 --- a/src/models/generated/Line.jl +++ b/src/models/generated/Line.jl @@ -16,6 +16,7 @@ This file is auto-generated. Do not edit. b::FromTo rating::Float64 angle_limits::MinMax + g::FromTo services::Vector{Service} ext::Dict{String, Any} internal::InfrastructureSystemsInternal @@ -34,6 +35,7 @@ An AC transmission line - `b::FromTo`: Shunt susceptance in pu ([`SYSTEM_BASE`](@ref per_unit)), specified both on the `from` and `to` ends of the line. These are commonly modeled with the same value, validation range: `(0, 100)` - `rating::Float64`: Thermal rating (MVA). Flow on the line must be between -`rating` and `rating`. When defining a line before it is attached to a `System`, `rating` must be in per-unit divided by the base power of the `System` it will be attached to - `angle_limits::MinMax`: Minimum and maximum angle limits (radians), validation range: `(-1.571, 1.571)` +- `g::FromTo`: (default: `(from=0.0, to=0.0)`) Shunt conductance in pu ([`SYSTEM_BASE`](@ref per_unit)), specified both on the `from` and `to` ends of the line. These are commonly modeled with the same value, validation range: `(0, 100)` - `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to - `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation, such as latitude and longitude. - `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference @@ -59,6 +61,8 @@ mutable struct Line <: ACBranch rating::Float64 "Minimum and maximum angle limits (radians)" angle_limits::MinMax + "Shunt conductance in pu ([`SYSTEM_BASE`](@ref per_unit)), specified both on the `from` and `to` ends of the line. These are commonly modeled with the same value" + g::FromTo "Services that this device contributes to" services::Vector{Service} "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation, such as latitude and longitude." @@ -67,12 +71,12 @@ mutable struct Line <: ACBranch internal::InfrastructureSystemsInternal end -function Line(name, available, active_power_flow, reactive_power_flow, arc, r, x, b, rating, angle_limits, services=Device[], ext=Dict{String, Any}(), ) - Line(name, available, active_power_flow, reactive_power_flow, arc, r, x, b, rating, angle_limits, services, ext, InfrastructureSystemsInternal(), ) +function Line(name, available, active_power_flow, reactive_power_flow, arc, r, x, b, rating, angle_limits, g=(from=0.0, to=0.0), services=Device[], ext=Dict{String, Any}(), ) + Line(name, available, active_power_flow, reactive_power_flow, arc, r, x, b, rating, angle_limits, g, services, ext, InfrastructureSystemsInternal(), ) end -function Line(; name, available, active_power_flow, reactive_power_flow, arc, r, x, b, rating, angle_limits, services=Device[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), ) - Line(name, available, active_power_flow, reactive_power_flow, arc, r, x, b, rating, angle_limits, services, ext, internal, ) +function Line(; name, available, active_power_flow, reactive_power_flow, arc, r, x, b, rating, angle_limits, g=(from=0.0, to=0.0), services=Device[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), ) + Line(name, available, active_power_flow, reactive_power_flow, arc, r, x, b, rating, angle_limits, g, services, ext, internal, ) end # Constructor for demo purposes; non-functional. @@ -88,6 +92,7 @@ function Line(::Nothing) b=(from=0.0, to=0.0), rating=0.0, angle_limits=(min=-1.571, max=1.571), + g=(from=0.0, to=0.0), services=Device[], ext=Dict{String, Any}(), ) @@ -113,6 +118,8 @@ get_b(value::Line) = value.b get_rating(value::Line) = get_value(value, value.rating) """Get [`Line`](@ref) `angle_limits`.""" get_angle_limits(value::Line) = value.angle_limits +"""Get [`Line`](@ref) `g`.""" +get_g(value::Line) = value.g """Get [`Line`](@ref) `services`.""" get_services(value::Line) = value.services """Get [`Line`](@ref) `ext`.""" @@ -138,6 +145,8 @@ set_b!(value::Line, val) = value.b = val set_rating!(value::Line, val) = value.rating = set_value(value, val) """Set [`Line`](@ref) `angle_limits`.""" set_angle_limits!(value::Line, val) = value.angle_limits = val +"""Set [`Line`](@ref) `g`.""" +set_g!(value::Line, val) = value.g = val """Set [`Line`](@ref) `services`.""" set_services!(value::Line, val) = value.services = val """Set [`Line`](@ref) `ext`.""" diff --git a/src/models/generated/MonitoredLine.jl b/src/models/generated/MonitoredLine.jl index 3ba2d6e195..4ae1230109 100644 --- a/src/models/generated/MonitoredLine.jl +++ b/src/models/generated/MonitoredLine.jl @@ -17,6 +17,7 @@ This file is auto-generated. Do not edit. flow_limits::FromTo_ToFrom rating::Float64 angle_limits::MinMax + g::FromTo services::Vector{Service} ext::Dict{String, Any} internal::InfrastructureSystemsInternal @@ -38,6 +39,7 @@ For example, monitored lines can be used to restrict line flow following a conti - `flow_limits::FromTo_ToFrom`: Minimum and maximum permissable flow on the line (MVA), if different from the thermal rating defined in `rating` - `rating::Float64`: Thermal rating (MVA). Flow through the transformer must be between -`rating` and `rating`. When defining a line before it is attached to a `System`, `rating` must be in per-unit divided by the base power of the `System` it will be attached to - `angle_limits::MinMax`: Minimum and maximum angle limits (radians), validation range: `(-1.571, 1.571)` +- `g::FromTo`: (default: `(from=0.0, to=0.0)`) Shunt conductance in pu ([`SYSTEM_BASE`](@ref per_unit)), specified both on the `from` and `to` ends of the line. These are commonly modeled with the same value, validation range: `(0, 100)` - `services::Vector{Service}`: (default: `Device[]`) Services that this device contributes to - `ext::Dict{String, Any}`: (default: `Dict{String, Any}()`) An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation, such as latitude and longitude. - `internal::InfrastructureSystemsInternal`: (**Do not modify.**) PowerSystems.jl internal reference @@ -65,6 +67,8 @@ mutable struct MonitoredLine <: ACBranch rating::Float64 "Minimum and maximum angle limits (radians)" angle_limits::MinMax + "Shunt conductance in pu ([`SYSTEM_BASE`](@ref per_unit)), specified both on the `from` and `to` ends of the line. These are commonly modeled with the same value" + g::FromTo "Services that this device contributes to" services::Vector{Service} "An [*ext*ra dictionary](@ref additional_fields) for users to add metadata that are not used in simulation, such as latitude and longitude." @@ -73,12 +77,12 @@ mutable struct MonitoredLine <: ACBranch internal::InfrastructureSystemsInternal end -function MonitoredLine(name, available, active_power_flow, reactive_power_flow, arc, r, x, b, flow_limits, rating, angle_limits, services=Device[], ext=Dict{String, Any}(), ) - MonitoredLine(name, available, active_power_flow, reactive_power_flow, arc, r, x, b, flow_limits, rating, angle_limits, services, ext, InfrastructureSystemsInternal(), ) +function MonitoredLine(name, available, active_power_flow, reactive_power_flow, arc, r, x, b, flow_limits, rating, angle_limits, g=(from=0.0, to=0.0), services=Device[], ext=Dict{String, Any}(), ) + MonitoredLine(name, available, active_power_flow, reactive_power_flow, arc, r, x, b, flow_limits, rating, angle_limits, g, services, ext, InfrastructureSystemsInternal(), ) end -function MonitoredLine(; name, available, active_power_flow, reactive_power_flow, arc, r, x, b, flow_limits, rating, angle_limits, services=Device[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), ) - MonitoredLine(name, available, active_power_flow, reactive_power_flow, arc, r, x, b, flow_limits, rating, angle_limits, services, ext, internal, ) +function MonitoredLine(; name, available, active_power_flow, reactive_power_flow, arc, r, x, b, flow_limits, rating, angle_limits, g=(from=0.0, to=0.0), services=Device[], ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), ) + MonitoredLine(name, available, active_power_flow, reactive_power_flow, arc, r, x, b, flow_limits, rating, angle_limits, g, services, ext, internal, ) end # Constructor for demo purposes; non-functional. @@ -95,6 +99,7 @@ function MonitoredLine(::Nothing) flow_limits=(from_to=0.0, to_from=0.0), rating=0.0, angle_limits=(min=-1.571, max=1.571), + g=(from=0.0, to=0.0), services=Device[], ext=Dict{String, Any}(), ) @@ -122,6 +127,8 @@ get_flow_limits(value::MonitoredLine) = get_value(value, value.flow_limits) get_rating(value::MonitoredLine) = get_value(value, value.rating) """Get [`MonitoredLine`](@ref) `angle_limits`.""" get_angle_limits(value::MonitoredLine) = value.angle_limits +"""Get [`MonitoredLine`](@ref) `g`.""" +get_g(value::MonitoredLine) = value.g """Get [`MonitoredLine`](@ref) `services`.""" get_services(value::MonitoredLine) = value.services """Get [`MonitoredLine`](@ref) `ext`.""" @@ -149,6 +156,8 @@ set_flow_limits!(value::MonitoredLine, val) = value.flow_limits = set_value(valu set_rating!(value::MonitoredLine, val) = value.rating = set_value(value, val) """Set [`MonitoredLine`](@ref) `angle_limits`.""" set_angle_limits!(value::MonitoredLine, val) = value.angle_limits = val +"""Set [`MonitoredLine`](@ref) `g`.""" +set_g!(value::MonitoredLine, val) = value.g = val """Set [`MonitoredLine`](@ref) `services`.""" set_services!(value::MonitoredLine, val) = value.services = val """Set [`MonitoredLine`](@ref) `ext`.""" diff --git a/src/models/generated/includes.jl b/src/models/generated/includes.jl index 1d50632cab..9f4dbbf26a 100644 --- a/src/models/generated/includes.jl +++ b/src/models/generated/includes.jl @@ -528,6 +528,7 @@ export get_from_branch_control export get_fs export get_fuel export get_fuel_flag +export get_g export get_gate_openings export get_gate_position_limits export get_hysteresis_binary_logic @@ -1093,6 +1094,7 @@ export set_from_branch_control! export set_fs! export set_fuel! export set_fuel_flag! +export set_g! export set_gate_openings! export set_gate_position_limits! export set_hysteresis_binary_logic! diff --git a/src/parsers/pm_io/data.jl b/src/parsers/pm_io/data.jl index d35bd6e497..ff7ce19ee4 100644 --- a/src/parsers/pm_io/data.jl +++ b/src/parsers/pm_io/data.jl @@ -1695,10 +1695,7 @@ function correct_bus_types!(data::Dict{String, <:Any}) end if bus_gens_count != 0 && bus["bus_type"] != 2 - @info "active generators found at bus $(bus["bus_i"]), updating to bus type from $(bus["bus_type"]) to 2" maxlog = - PS_MAX_LOG - bus["bus_type"] = 2 - push!(modified, bus["index"]) + @warn "active generators found at bus $(bus["bus_i"]) on bus type $(bus["bus_type"]), i.e. different than 2 (PV). Consider checking your data inputs." end end end diff --git a/src/parsers/power_models_data.jl b/src/parsers/power_models_data.jl index 4880060867..0973f3338e 100644 --- a/src/parsers/power_models_data.jl +++ b/src/parsers/power_models_data.jl @@ -326,7 +326,6 @@ function read_loadzones!( kwargs..., ) @info "Reading LoadZones data in PowerModels dict to populate System ..." - _get_name = get(kwargs, :loadzone_name_formatter, _get_pm_dict_name) zones = Set{Int}() zone_bus_map = Dict{Int, Vector}() for (_, bus) in data["bus"] @@ -346,9 +345,15 @@ function read_loadzones!( load_zone_map[zone]["pd"] += get(load, "py", 0.0) load_zone_map[zone]["qd"] += get(load, "qy", 0.0) end + + default_loadzone_naming = string + # The formatter for loadzone_name should be a function that transform the LoadZone Int to a String + _get_name = get(kwargs, :loadzone_name_formatter, default_loadzone_naming) + for zone in zones + name = _get_name(zone) load_zone = make_loadzone( - string(zone), + name, load_zone_map[zone]["pd"], load_zone_map[zone]["qd"]; kwargs..., diff --git a/src/utils/IO/system_checks.jl b/src/utils/IO/system_checks.jl index c5474499c1..24bfab8704 100644 --- a/src/utils/IO/system_checks.jl +++ b/src/utils/IO/system_checks.jl @@ -123,7 +123,7 @@ Sum of system generator and storage ratings. function total_capacity_rating(sys::System) total = 0 for component_type in (Generator, Storage) - components = get_components(Generator, sys) + components = get_components(component_type, sys) if !isempty(components) component_total = sum(get_rating.(components)) * get_base_power(sys) @debug "total rating for $component_type = $component_total" _group = diff --git a/src/utils/print.jl b/src/utils/print.jl index ec78adcd70..10de3766b6 100644 --- a/src/utils/print.jl +++ b/src/utils/print.jl @@ -298,3 +298,10 @@ show_components( additional_columns::Union{Dict, Vector} = Dict(); kwargs..., ) = show_components(io, sys, component_type, additional_columns; kwargs...) + +""" +Show a table with the summary of time series attached to the system. +""" +function show_time_series(sys::System) + IS.show_time_series_data(stdout, sys.data) +end diff --git a/test/test_parse_psse.jl b/test/test_parse_psse.jl index ba1c639f89..e31f34bc7b 100644 --- a/test/test_parse_psse.jl +++ b/test/test_parse_psse.jl @@ -36,4 +36,15 @@ end @test get_available(get_component(ThermalStandard, sys, "generator-2438-ND")) == 0 @test get_status(get_component(ThermalStandard, sys, "generator-2438-EG")) == 1 @test get_available(get_component(ThermalStandard, sys, "generator-2438-EG")) == 1 + + @info "Testing Load Zone Formatter" + PSB.clear_serialized_systems("psse_Benchmark_4ger_33_2015_sys") + sys3 = build_system( + PSYTestSystems, + "psse_Benchmark_4ger_33_2015_sys"; + loadzone_name_formatter = x -> string(3 * x), + ) + lz_original = only(get_components(LoadZone, sys2)) + lz_new = only(get_components(LoadZone, sys3)) + @test parse(Int, get_name(lz_new)) == 3 * parse(Int, get_name(lz_original)) end