Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
f16cf24
Set temp URL for InfrastructureSystems
daniel-thom Jul 24, 2026
bf3a80b
clean up code cov
jd-lara Jul 30, 2026
fe1f44e
feat: add OpenAPI emit layer and drop the PowerSystemCaseBuilder test…
jd-lara Jul 30, 2026
d968cf0
test usage of the OpenAPI structs
jd-lara Jul 31, 2026
f7ff816
validation readme
jd-lara Jul 31, 2026
581c74f
Salvage line shunts from switching devices declared in BRANCH data
jd-lara Jul 31, 2026
35be103
Ignore .claude/plans/ working documents
jd-lara Jul 31, 2026
7f232aa
Remove .claude/Sienna.md in favor of the shared sienna-psy6 skill
jd-lara Aug 2, 2026
650d382
Rename .claude/claude.md to .claude/CLAUDE.md
jd-lara Aug 2, 2026
833f13f
test with TestData
jd-lara Aug 4, 2026
d7eae77
update code for OpenAPI spec
jd-lara Aug 6, 2026
dd8902b
Rebuild OpenAPISystem over PC.SystemDocument; add topology readers
jd-lara Aug 8, 2026
614a22e
Warn on unconsumed pm dict sections; fix units.jl model drift
jd-lara Aug 8, 2026
56890db
Add load and generation/cost readers to the OpenAPI emit layer
jd-lara Aug 8, 2026
31df73b
Add branch, transformer, DC line, and shunt readers to the OpenAPI em…
jd-lara Aug 8, 2026
848e819
Fix round 1: convert non-exempt ternaries to if/else, drop dead DC_VO…
jd-lara Aug 8, 2026
7298455
Add switch/breaker and attributes readers; close pm-section ledger; f…
jd-lara Aug 8, 2026
d1dcb5e
Replace VSC control-mode gap tests with real conversions; document kV…
jd-lara Aug 8, 2026
ebaef5a
Restore loud error for VSC voltage-control setpoints until reader car…
jd-lara Aug 8, 2026
aec7f0b
Simplify OpenAPI emit layer comments and structure
jd-lara Aug 8, 2026
b8d4f35
Implement real DEVICE_BASE emission in build_openapi_system
jd-lara Aug 8, 2026
de88e7e
Include ActivePowerChangeRate (ramp_limits) in DEVICE_BASE conversion
jd-lara Aug 8, 2026
3c92e50
Close instance-dispatched-field hole in DEVICE_BASE classification
jd-lara Aug 8, 2026
f097815
Fix TransformerCircuit.controlled_quantity_limits: static :skip, not …
jd-lara Aug 8, 2026
a22da2f
Settle transfer_setpoint DEVICE_BASE disposition: LCC exists only as …
jd-lara Aug 8, 2026
64e7802
Simplify sweep: drop plan-reference comments, factor ext/optional-val…
jd-lara Aug 9, 2026
8b1004a
Merge branch 'feat/rust-time-series-store' into dt/openapi-json-expor…
daniel-thom Aug 11, 2026
3b3e5fa
Emit service memberships as ServiceAssociation rows
daniel-thom Aug 14, 2026
bcff418
Assert the plant/service tables stay empty for a plain attribute link
daniel-thom Aug 14, 2026
879d3c5
Update for infrastore integration
daniel-thom Aug 17, 2026
670ec32
Merge branch 'psy6' into feat/infrastore-integration
daniel-thom Aug 17, 2026
0af78ea
Migrate to the split OpenAPI packages
jd-lara Aug 20, 2026
477c3cc
Fill component_id and component_type on shared attribute associations
jd-lara Aug 21, 2026
41988ee
Track the umbrella package's new UUID
jd-lara Aug 21, 2026
62c506b
Apply the review cleanup across the parser and OpenAPI construction
jd-lara Aug 22, 2026
c112ba1
Capture each VSC converter's AC voltage base from the raw file
jd-lara Aug 22, 2026
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: 5 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
OpenAPI = "d5e62ea6-ddf3-4d43-8e4c-ad5e6c8bfd7d"
PowerCoreOpenAPIModels = "b7b40286-e793-417d-a9a0-b1583e4da1cb"
PowerOpenAPIModels = "0730f07c-cff6-4c3b-a9df-c546153be50a"
PowerOperationsOpenAPIModels = "a372b6d7-45a2-44c2-8199-6a724b72e8ff"
Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"

[sources]
# These packages are generated and not yet released, so they resolve from the branch
# rather than the registry. Switch to a tagged rev once one exists.
PowerCoreOpenAPIModels = {url = "https://github.com/Sienna-Platform/PowerOpenAPIModels.git", rev = "jd/openapi_regen", subdir = "PowerCoreOpenAPIModels.jl"}
PowerOperationsOpenAPIModels = {url = "https://github.com/Sienna-Platform/PowerOpenAPIModels.git", rev = "jd/openapi_regen", subdir = "PowerOperationsOpenAPIModels.jl"}
PowerCoreOpenAPIModels = {url = "https://github.com/Sienna-Platform/PowerOpenAPIModels.git", rev = "feat/infrastore-integration", subdir = "PowerCoreOpenAPIModels.jl"}
PowerOperationsOpenAPIModels = {url = "https://github.com/Sienna-Platform/PowerOpenAPIModels.git", rev = "feat/infrastore-integration", subdir = "PowerOperationsOpenAPIModels.jl"}
InfrastructureSystems = {rev = "feat/infrastore-integration", url = "https://github.com/Sienna-Platform/InfrastructureSystems.jl"}

[compat]
DataStructures = "0.19.3"
Expand All @@ -28,6 +30,7 @@ JSON = "1"
LinearAlgebra = "1"
OpenAPI = "0.2"
PowerCoreOpenAPIModels = "0.1"
PowerOpenAPIModels = "0.1"
PowerOperationsOpenAPIModels = "0.1"
Unicode = "1"
julia = "^1.10"
4 changes: 2 additions & 2 deletions docs/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ PowerOperationsOpenAPIModels = "a372b6d7-45a2-44c2-8199-6a724b72e8ff"
# pin them.
[sources]
PowerFlowFileParser = {path = ".."}
PowerCoreOpenAPIModels = {url = "https://github.com/Sienna-Platform/PowerOpenAPIModels.git", rev = "jd/openapi_regen", subdir = "PowerCoreOpenAPIModels.jl"}
PowerOperationsOpenAPIModels = {url = "https://github.com/Sienna-Platform/PowerOpenAPIModels.git", rev = "jd/openapi_regen", subdir = "PowerOperationsOpenAPIModels.jl"}
PowerCoreOpenAPIModels = {url = "https://github.com/Sienna-Platform/PowerOpenAPIModels.git", rev = "feat/infrastore-integration", subdir = "PowerCoreOpenAPIModels.jl"}
PowerOperationsOpenAPIModels = {url = "https://github.com/Sienna-Platform/PowerOpenAPIModels.git", rev = "feat/infrastore-integration", subdir = "PowerOperationsOpenAPIModels.jl"}

[compat]
julia = "^1.10"
Expand Down
2 changes: 2 additions & 0 deletions src/PowerFlowFileParser.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import Unicode: normalize
import JSON
import OpenAPI
import PowerCoreOpenAPIModels
import PowerOpenAPIModels
import PowerOperationsOpenAPIModels
const PC = PowerCoreOpenAPIModels
const PD = PowerOpenAPIModels
const PO = PowerOperationsOpenAPIModels

import InfrastructureSystems
Expand Down
21 changes: 13 additions & 8 deletions src/openapi/attributes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

"""
One piecewise-linear curve and control-mode per impedance-correction table number.
Ported from PSCB's `_impedance_correction_table_lookup` (:213-261), minus the per-winding
Ported from PSCB's `_impedance_correction_table_lookup`, minus the per-winding
pre-expansion — [`_attach_impedance_correction!`](@ref) does that lazily, only for
(table, winding) pairs a transformer actually references.
"""
Expand Down Expand Up @@ -78,7 +78,8 @@ function _new_impedance_correction_attribute!(
end

"""
Attach the `ImpedanceCorrectionData` for `(d[table_key], winding)` to `transformer_id`,
Attach the `ImpedanceCorrectionData` for `(d[table_key], winding)` to `transformer_id`
(a `transformer_type` component: `"TwoWindingTransformer"` or `"ThreeWindingTransformer"`),
if `d[table_key]` names a table `curves` has an entry for. `table_key` absent, or naming
table `0` (PSS/E's "no correction table" default, per `pti.jl`'s TAB1/TAB2/TAB3
defaults), is a no-op — matching PSCB's `_attach_single_ict!`, which only ever finds a
Expand All @@ -94,6 +95,7 @@ function _attach_impedance_correction!(
table_key::AbstractString,
winding::AbstractString,
transformer_id::Int,
transformer_type::AbstractString,
)
if isempty(curves) || !haskey(d, table_key)
return
Expand All @@ -105,7 +107,9 @@ function _attach_impedance_correction!(
key = (table_number, winding)
if haskey(cache, key)
# The attribute already exists, so only the association row is new.
add_supplemental_attribute_association!(sys, cache[key], transformer_id)
add_supplemental_attribute_association!(
sys, cache[key], transformer_id, transformer_type,
)
else
cache[key] =
_new_impedance_correction_attribute!(sys, curves, table_number, winding,
Expand Down Expand Up @@ -142,7 +146,7 @@ function read_substations!(sys::OpenAPISystem, data::Dict; kwargs...)
set_value!(attribute, :grounding_resistance, d["grounding_resistance"], "ohm")
add_supplemental_attribute!(sys, attribute, first(bus_ids))
for bus_id in Iterators.drop(bus_ids, 1)
add_supplemental_attribute_association!(sys, attribute, bus_id)
add_supplemental_attribute_association!(sys, attribute, bus_id, "ACBus")
end
end
return
Expand All @@ -151,7 +155,7 @@ end
"""
Attach `ImpedanceCorrectionData` supplemental attributes to every `TwoWindingTransformer`/
`ThreeWindingTransformer` that references an impedance-correction table. Ported from
PSCB's `_attach_impedance_correction_tables!` (:294-330), but driven by re-walking
PSCB's `_attach_impedance_correction_tables!`, but driven by re-walking
`data["branch"]`/`data["3w_transformer"]` rather than called inline from the transformer
readers — so the name derivation below must match
[`read_branches!`](@ref)/[`read_3w_transformers!`](@ref) exactly, same formatter kwargs
Expand Down Expand Up @@ -179,6 +183,7 @@ function read_impedance_corrections!(sys::OpenAPISystem, data::Dict; kwargs...)
transformer_id = get_id(reg, "TwoWindingTransformer", name)
_attach_impedance_correction!(
sys, cache, curves, d, "correction_table", "TR2W_WINDING", transformer_id,
"TwoWindingTransformer",
)
end

Expand All @@ -197,15 +202,15 @@ function read_impedance_corrections!(sys::OpenAPISystem, data::Dict; kwargs...)
transformer_id = get_id(reg, "ThreeWindingTransformer", name)
_attach_impedance_correction!(
sys, cache, curves, d, "primary_correction_table", "PRIMARY_WINDING",
transformer_id,
transformer_id, "ThreeWindingTransformer",
)
_attach_impedance_correction!(
sys, cache, curves, d, "secondary_correction_table", "SECONDARY_WINDING",
transformer_id,
transformer_id, "ThreeWindingTransformer",
)
_attach_impedance_correction!(
sys, cache, curves, d, "tertiary_correction_table", "TERTIARY_WINDING",
transformer_id,
transformer_id, "ThreeWindingTransformer",
)
end
return
Expand Down
37 changes: 14 additions & 23 deletions src/openapi/branch.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,6 @@ function _get_rating(name::AbstractString, d::Dict, key::AbstractString)
return d[key]
end

"""A `_get_rating`-style optional value (`nothing` when the pm dict carries no such key),
scaled onto the circuit's own `base_power`."""
function _scaled_or_nothing(value, base_power::Real)
if isnothing(value)
return nothing
end
return value * base_power
end

"""Bus name and ISOLATED status by pm bus number. Shared by the branch/transformer/
dc-line/shunt readers, all of which resolve endpoints by pm bus number rather than by
document id."""
Expand Down Expand Up @@ -267,7 +258,7 @@ function _make_transformer_circuit!(
set_value!(circuit, :arc, arc_id)
set_value!(circuit, :tap, get(d, tap_key, 1.0), "1")
set_value!(circuit, :alpha, d[angle_key], "rad")
set_value!(circuit, :parameter_units, "DEVICE_BASE")
set_value!(circuit, :parameter_units, "COMPONENT_BASE")
set_value!(circuit, :r, r, "pu")
set_value!(circuit, :x, x, "pu")
_set_transformer_control_fields!(circuit, d, control_suffix, record)
Expand Down Expand Up @@ -315,17 +306,17 @@ function make_line!(
set_value!(line, :b, (from = d["b_fr"], to = d["b_to"]), "pu")
set_value!(line, :rating, _get_rating(name, d, "rate_a") * sys_mbase, "MVA")
set_optional_value!(line, :rating_b,
_scaled_or_nothing(_get_rating(name, d, "rate_b"), sys_mbase), "MVA")
_natural_value(_get_rating(name, d, "rate_b"), sys_mbase), "MVA")
set_optional_value!(line, :rating_c,
_scaled_or_nothing(_get_rating(name, d, "rate_c"), sys_mbase), "MVA")
_natural_value(_get_rating(name, d, "rate_c"), sys_mbase), "MVA")
set_value!(line, :angle_limits, (min = d["angmin"], max = d["angmax"]), "rad")
add_component!(sys, line)
set_component_ext!(sys, line, get(d, "ext", Dict{String, Any}()))
return
end

"""A zero-impedance pm branch, converted to a `DiscreteControlledACBranch` of type
`SWITCH`. Ported from PSCB's `_make_switch_from_zero_impedance_line` (:1270-1301) — a
`SWITCH`. Ported from PSCB's `_make_switch_from_zero_impedance_line` — a
real PSS/E data shape (a modeled switching device recorded as a zero-r/x branch), not one
of the four named bug-compatible sites."""
function make_switch_from_zero_impedance_branch!(
Expand Down Expand Up @@ -370,7 +361,7 @@ function _branch_type_matpower(d::Dict)
shift = d["shift"]
is_transformer = d["transformer"]
if !is_transformer
is_transformer = (tap != 0.0 && tap != 1.0) || shift != 0.0
is_transformer = (!iszero(tap) && tap != 1.0) || !iszero(shift)
end
if is_transformer
return :transformer
Expand All @@ -385,7 +376,7 @@ function _branch_type_psse(d::Dict, name::AbstractString)
is_transformer = d["transformer"]
tap = d["tap"]
if !is_transformer
if tap != 0.0 && tap != 1.0
if !iszero(tap) && tap != 1.0
@warn "Transformer $name has tap ratio $tap, which is not 0.0 or 1.0; this is not a valid value for a Line. Parsing entry as a Transformer"
else
return :line
Expand All @@ -395,7 +386,7 @@ function _branch_type_psse(d::Dict, name::AbstractString)
end

"""Two-winding transformer + its `TransformerCircuit`. Ported from PSCB's
`make_transformer_2w` (:1503-1553). See the file header for the rating/flow base
`make_transformer_2w`. See the file header for the rating/flow base
(circuit's own `base_power`, not `sys_mbase`) and the magnetizing shunt basis
(`g_fr`/`b_fr` are already device-base pu for PSS/E-origin data; identical to system base
for MATPOWER, where `base_power == sys_mbase` unconditionally)."""
Expand All @@ -420,9 +411,9 @@ function make_transformer_2w!(
tap_key = "tap", angle_key = "shift", control_suffix = 1,
available = available,
r = d["br_r"], x = d["br_x"],
rating = _scaled_or_nothing(rate_a, base_power),
rating_b = _scaled_or_nothing(rate_b, base_power),
rating_c = _scaled_or_nothing(rate_c, base_power),
rating = _natural_value(rate_a, base_power),
rating_b = _natural_value(rate_b, base_power),
rating_c = _natural_value(rate_c, base_power),
base_power = base_power,
base_voltage_primary = _base_voltage_or_nothing(d["base_voltage_from"]),
base_voltage_secondary = _base_voltage_or_nothing(d["base_voltage_to"]),
Expand All @@ -434,7 +425,7 @@ function make_transformer_2w!(
set_value!(component, :id, register!(reg, "TwoWindingTransformer", name))
set_value!(component, :name, name)
set_value!(component, :circuit, circuit_id)
set_value!(component, :admittance_units, "DEVICE_BASE")
set_value!(component, :admittance_units, "COMPONENT_BASE")
set_value!(component, :magnetizing_shunt, (real = d["g_fr"], imag = d["b_fr"]), "pu")
add_component!(sys, component)
set_component_ext!(sys, component, get(d, "ext", Dict{String, Any}()))
Expand Down Expand Up @@ -505,7 +496,7 @@ function make_3w_transformer!(
set_value!(component, :secondary_circuit, secondary_circuit)
set_value!(component, :tertiary_circuit, tertiary_circuit)
set_value!(component, :star_bus, star_id)
set_value!(component, :parameter_units, "DEVICE_BASE")
set_value!(component, :parameter_units, "COMPONENT_BASE")
set_value!(component, :r_12, d["r_12"], "pu")
set_value!(component, :x_12, d["x_12"], "pu")
set_value!(component, :r_23, d["r_23"], "pu")
Expand All @@ -515,7 +506,7 @@ function make_3w_transformer!(
set_value!(component, :base_power_12, d["base_power_12"], "MVA")
set_value!(component, :base_power_23, d["base_power_23"], "MVA")
set_value!(component, :base_power_31, d["base_power_31"], "MVA")
set_value!(component, :admittance_units, "DEVICE_BASE")
set_value!(component, :admittance_units, "COMPONENT_BASE")
set_value!(component, :magnetizing_shunt, (real = d["g"], imag = d["b"]), "pu")
add_component!(sys, component)
set_component_ext!(sys, component, get(d, "ext", Dict{String, Any}()))
Expand Down Expand Up @@ -578,7 +569,7 @@ end

"""
Create one `ThreeWindingTransformer` per `data["3w_transformer"]` entry. Ported from
PSCB's `read_3w_transformer!` (:1685-1721). `data["3w_transformer"]`'s star bus is a
PSCB's `read_3w_transformer!`. `data["3w_transformer"]`'s star bus is a
regular pm dict bus entry (already an `ACBus` by the time this reader runs, via
`read_bus!`), not created here.
"""
Expand Down
2 changes: 1 addition & 1 deletion src/openapi/build.jl
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ a caller never mistakes a partial document for a complete one.

`unit_system` selects the convention the values are stored in, same as
[`OpenAPISystem`](@ref): `"NATURAL_UNITS"` (the default) leaves every reader's MW/MVAr/MVA
values as computed; `"DEVICE_BASE"` additionally runs [`apply_device_base_conversion!`](@ref)
values as computed; `"COMPONENT_BASE"` additionally runs [`apply_device_base_conversion!`](@ref)
over the built document, converting every power-family field into per-unit on the
component's own device base (or the system base, for the few types with none of their own) —
the document PowerSystems' `DeviceBaseUnit` importer expects. Keyword arguments — the
Expand Down
Loading
Loading