Skip to content

Commit

Permalink
Add Storage to exporter, resolve minor TODOs
Browse files Browse the repository at this point in the history
  • Loading branch information
GabrielKS committed Feb 5, 2025
1 parent 0191ce3 commit 91228e8
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 9 deletions.
6 changes: 6 additions & 0 deletions src/common.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ function get_reactive_power_limits_for_power_flow(gen::PSY.RenewableNonDispatch)
return (min = val, max = val)
end

function get_reactive_power_limits_for_power_flow(gen::PSY.Storage)
limits = PSY.get_reactive_power_limits(gen)
isnothing(limits) && return (min = -Inf, max = Inf) # TODO decide on proper behavior in this case
return limits
end

"""
Return the active power limits that should be used in power flow calculations and PSS/E
exports. Redirects to `PSY.get_active_power_limits` in all but special cases.
Expand Down
16 changes: 13 additions & 3 deletions src/psse_export.jl
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,8 @@ end

"""
If the export_settings flag `sources_as_generators` is set, export `PSY.Source` instances as
PSS/E generators in addition to `PSY.Generator`s
PSS/E generators in addition to `PSY.Generator`s. Same for `storages_as_generators` and
`PSY.Storage`.
WRITTEN TO SPEC: PSS/E 33.3 POM 5.2.1 Generator Data
"""
Expand All @@ -726,6 +727,13 @@ function write_to_buffers!(
by = PSY.get_name,
),
)
get(md["export_settings"], "storages_as_generators", false) && append!(
temp_gens,
sort!(
collect(PSY.get_components(PSY.Storage, exporter.system));
by = PSY.get_name,
),
)
return temp_gens
end
generator_name_mapping = get!(exporter.components_cache, "generator_name_mapping") do
Expand Down Expand Up @@ -1000,7 +1008,9 @@ function write_to_buffers!(
CZ = 1 # NOTE on parsing we do the transformation to this unit system
CM = 1 # NOTE on parsing we do the transformation to this unit system
MAG1 = PSSE_DEFAULT
MAG2 = -PSY.get_primary_shunt(transformer) # TODO check sign on parsing. We want the value stored in the Sienna field to be positive
MAG2 = -PSY.get_primary_shunt(transformer)
(MAG2 > 0) &&
@warn "Detected positive MAG2 for transformer $(PSY.get_name(transformer)) due to negative `get_primary_shunt`; exporting anyway"
NMETR = PSSE_DEFAULT
NAME = _psse_quote_string(transformer_name_mapping[PSY.get_name(transformer)])
STAT = PSY.get_available(transformer) ? 1 : 0
Expand Down Expand Up @@ -1183,6 +1193,7 @@ function write_export(
export_settings["overwrite"] = exporter.overwrite
export_settings["step"] = _step_to_string(exporter.step)
export_settings["sources_as_generators"] = true
export_settings["storages_as_generators"] = true

md["record_groups"] = OrderedDict{String, Bool}() # Keep track of which record groups we actually write to and which we skip

Expand Down Expand Up @@ -1247,7 +1258,6 @@ function get_psse_export_paths(
end

# COMMON INTERFACE
# TODO handle kwargs
make_power_flow_container(pfem::PSSEExportPowerFlow, sys::PSY.System; kwargs...) =
PSSEExporter(
sys,
Expand Down
12 changes: 6 additions & 6 deletions test/test_psse_export.jl
Original file line number Diff line number Diff line change
Expand Up @@ -189,19 +189,19 @@ function compare_systems_loosely(sys1::PSY.System, sys2::PSY.System;
end

# Extra checks for other types of generators
GenSource = Union{Generator, Source}
gen1_names = sort(PSY.get_name.(PSY.get_components(GenSource, sys1)))
gen2_names = sort(PSY.get_name.(PSY.get_components(GenSource, sys2)))
GenLike = Union{Generator, Source, Storage}
gen1_names = sort(PSY.get_name.(PSY.get_components(GenLike, sys1)))
gen2_names = sort(PSY.get_name.(PSY.get_components(GenLike, sys2)))
if gen1_names != gen2_names
@error "Predicted Generator/Source names do not match actual generator names"
@error "Predicted Generator/Source/Storage names do not match actual generator names"
@error "Predicted: $gen1_names"
@error "Actual: $gen2_names"
result = false
end
gen_common_names = intersect(gen1_names, gen2_names)
for (gen1, gen2) in zip(
PSY.get_component.(GenSource, [sys1], gen_common_names),
PSY.get_component.(GenSource, [sys2], gen_common_names),
PSY.get_component.(GenLike, [sys1], gen_common_names),
PSY.get_component.(GenLike, [sys2], gen_common_names),
)
# Skip pairs we've already compared
# e.g., if they're both ThermalStandards, we've already compared them
Expand Down

0 comments on commit 91228e8

Please sign in to comment.