diff --git a/.claude/Sienna.md b/.claude/Sienna.md index 1909c23..cd43389 100644 --- a/.claude/Sienna.md +++ b/.claude/Sienna.md @@ -1,13 +1,13 @@ # Sienna Programming Practices — psy6 / Sienna 1.0 line -General practices and cross-package architecture for the **psy6 (Sienna 1.0) development line**. This file is intended to be **identical across every repo under `/home/jdlara/Sienna_work/psy6/`** — package-specific guidance belongs in that repo's `.claude/CLAUDE.md`, and workspace wiring/policy in `/home/jdlara/Sienna_work/psy6/CLAUDE.md`. The psy5 (released) line at the workspace top level has its own copy of this file; never mix checkouts between the two lines. +General practices and cross-package architecture for the **psy6 (Sienna 1.0) development line**. This file is intended to be **identical across every repo in the psy6 workspace** — package-specific guidance belongs in that repo's `.claude/CLAUDE.md`, and workspace wiring/policy in the psy6 workspace root `CLAUDE.md`. The psy5 (released) line at the workspace top level has its own copy of this file; never mix checkouts between the two lines. ## Start here (fresh-session reading order) 1. This file — shared practices, the stack, and the vocabulary (glossary at the end). 2. The current repo's `.claude/CLAUDE.md` — package specifics, verified commands, gotchas. -3. `/home/jdlara/Sienna_work/psy6/CLAUDE.md` — workspace architecture, design decisions, seams, and the knowledge index (audit, active plans). -4. `/home/jdlara/Sienna_work/CLAUDE.md` — the two-line workspace layout and git/test policy. +3. the psy6 workspace root `CLAUDE.md` — workspace architecture, design decisions, seams, and the knowledge index (audit, active plans). +4. the workspace top-level `CLAUDE.md` (one level above the psy6 root) — the two-line workspace layout and git/test policy. If you are porting anything from the psy5 line (or reading psy5-era docs/PRs), read the psy5 → psy6 translation map below first — many psy5 facts are actively wrong here. @@ -46,7 +46,7 @@ Blast-radius quick reference — after changing: Downstream smoke check after upstream edits: ```sh -julia --project=/home/jdlara/Sienna_work/psy6 -e 'using PowerNetworkMatrices, PowerFlows, PowerOperationsModels, PowerSystemCaseBuilder' +julia --project= -e 'using PowerNetworkMatrices, PowerFlows, PowerOperationsModels, PowerSystemCaseBuilder' ``` ## The data/schema pipeline (SiennaSchemas → OpenAPI models → SiennaGridDB) @@ -108,11 +108,11 @@ These exist in the codebase and are flagged for removal; new code must error lou ## Environments and testing in the psy6 workspace -- **Shared dev env:** `julia --project=/home/jdlara/Sienna_work/psy6` dev-wires all co-developed packages (rebuild with `psy6/wire_psy6.jl`). A dev'd dependency's own `[sources]` pins are ignored by the parent env — only the active project's count; that is why the shared env exists. +- **Shared dev env:** `julia --project=` dev-wires all co-developed packages (rebuild with the workspace's `wire_psy6.jl`). A dev'd dependency's own `[sources]` pins are ignored by the parent env — only the active project's count; that is why the shared env exists. - **Per-package `Pkg.test()` honors that package's own `[sources]` git pins**, not the shared env. To test against local checkouts, temporarily repoint that repo's `test/Project.toml` `[sources]` to local paths (restore before finishing). - **No version/compat bumps in any Project.toml until release** (PSY reads 5.10.0, IS 3.6.0 despite being the 6.0/4.0 lines). Bumps have reappeared spontaneously mid-session — revert them. - PSB cache: no version-aware invalidation — clear `data/serialized_system/` after PSY changes; the CaseData artifact download can flake (retry once). -- Python tooling: use `python3` (never `python`); the units venv is `/home/jdlara/Sienna_work/psy6/.venv-units`; **`just` is not installed** — run the underlying commands from the `.justfile` directly. +- Python tooling: use `python3` (never `python`); the units venv is `.venv-units` at the psy6 workspace root; **`just` is not installed** — run the underlying commands from the `.justfile` directly. ## Performance Requirements diff --git a/src/pm_io/psse.jl b/src/pm_io/psse.jl index 4b4b4d0..ad76f91 100644 --- a/src/pm_io/psse.jl +++ b/src/pm_io/psse.jl @@ -738,8 +738,12 @@ function _psse2pm_shunt!(pm_data::Dict, pti_data::Dict, import_all::Bool) sub_data["step_number"] = [step_numbers[k] for k in step_numbers_sorted] sub_data["step_number"] = sub_data["step_number"][sub_data["step_number"] .!= 0] + sub_data["control_mode"] = switched_shunt["MODSW"] + # pti.jl names the regulated-bus column "SWREM" for every source version, + # including v35 where the PSS/E spec itself calls it SWREG. + sub_data["regulated_bus_number"] = switched_shunt["SWREM"] + sub_data["ext"] = Dict{String, Any}( - "MODSW" => switched_shunt["MODSW"], "ADJM" => switched_shunt["ADJM"], "RMPCT" => switched_shunt["RMPCT"], "RMIDNT" => switched_shunt["RMIDNT"], @@ -770,7 +774,6 @@ function _psse2pm_shunt!(pm_data::Dict, pti_data::Dict, import_all::Bool) sub_data["ext"]["NREG"] = pop!(switched_shunt, "NREG") elseif pm_data["source_version"] ∈ ("30", "32", "33") - sub_data["ext"]["SWREM"] = switched_shunt["SWREM"] sub_data["initial_status"] = ones(Int, length(sub_data["y_increment"])) else error("Unsupported PSS(R)E source version: $(pm_data["source_version"])") @@ -1858,8 +1861,38 @@ function _psse2pm_dcline!(pm_data::Dict, pti_data::Dict, import_all::Bool) sub_data["ac_voltage_control_from"] = from_bus["MODE"] == 1 ? true : false sub_data["ac_voltage_control_to"] = to_bus["MODE"] == 1 ? true : false - sub_data["dc_setpoint_from"] = from_bus["DCSET"] - sub_data["dc_setpoint_to"] = to_bus["DCSET"] + if sub_data["dc_voltage_control_from"] && !sub_data["dc_voltage_control_to"] + base_voltage = from_bus["DCSET"] + flow_setpoint = to_bus["DCSET"] + elseif !sub_data["dc_voltage_control_from"] && sub_data["dc_voltage_control_to"] + base_voltage = to_bus["DCSET"] + flow_setpoint = -from_bus["DCSET"] + elseif !sub_data["dc_voltage_control_from"] && + !sub_data["dc_voltage_control_to"] + error( + "At least one converter in converter $(sub_data["name"]) must set a voltage control.", + ) + else + error( + "Exactly one converter in converter $(sub_data["name"]) must control DC voltage (TYPE = 1).", + ) + end + + # PSY documents dc_setpoint_from/to as p.u. of rated_dc_voltage for the + # DC-voltage-controlling side (TYPE = 1), and p.u. of baseMVA otherwise. + sub_data["rated_dc_voltage"] = base_voltage + sub_data["dc_setpoint_from"] = + if from_bus["TYPE"] == 1 + from_bus["DCSET"] / base_voltage + else + from_bus["DCSET"] / baseMVA + end + sub_data["dc_setpoint_to"] = + if to_bus["TYPE"] == 1 + to_bus["DCSET"] / base_voltage + else + to_bus["DCSET"] / baseMVA + end sub_data["ac_setpoint_from"] = from_bus["ACSET"] sub_data["ac_setpoint_to"] = to_bus["ACSET"] @@ -1903,17 +1936,6 @@ function _psse2pm_dcline!(pm_data::Dict, pti_data::Dict, import_all::Bool) sub_data["pminf"] = -sub_data["pmaxf"] sub_data["pmint"] = -sub_data["pmaxt"] - if sub_data["dc_voltage_control_from"] && !sub_data["dc_voltage_control_to"] - base_voltage = sub_data["dc_setpoint_from"] - flow_setpoint = sub_data["dc_setpoint_to"] - elseif !sub_data["dc_voltage_control_from"] && sub_data["dc_voltage_control_to"] - base_voltage = sub_data["dc_setpoint_to"] - flow_setpoint = -sub_data["dc_setpoint_from"] - else - error( - "At least one converter in converter $(sub_data["name"]) must set a voltage control.", - ) - end Zbase = base_voltage^2 / baseMVA sub_data["r"] = dcline["RDC"] / Zbase sub_data["pf"] = flow_setpoint / baseMVA @@ -1991,15 +2013,19 @@ function _psse2pm_facts!(pm_data::Dict, pti_data::Dict, import_all::Bool) @warn "% MVAr required must me positive." end - sub_data["reactive_power_required"] = facts["RMPCT"] sub_data["ext"] = Dict{String, Any}() if pm_data["source_version"] == "35" + sub_data["regulated_bus_number"] = facts["FCREG"] sub_data["ext"]["NREG"] = facts["NREG"] sub_data["ext"]["MNAME"] = facts["MNAME"] + sub_data["ext"]["RMPCT"] = facts["RMPCT"] elseif pm_data["source_version"] ∈ ("30", "32", "33") + # REMOT is absent from the v30 FACTS record layout (_FACTS_dtypes_v30) + sub_data["regulated_bus_number"] = get(facts, "REMOT", 0) sub_data["ext"] = Dict{String, Any}( "J" => facts["J"], + "RMPCT" => facts["RMPCT"], ) else error("Unsupported PSS(R)E source version: $(pm_data["source_version"])") diff --git a/src/pm_io/pti.jl b/src/pm_io/pti.jl index d85f998..7f1f84c 100644 --- a/src/pm_io/pti.jl +++ b/src/pm_io/pti.jl @@ -1523,15 +1523,6 @@ const _default_switched_shunt = Dict( "S8" => 1, "N8" => 0, "B8" => 0.0, ) -const _default_switched_shunt_v35 = merge( - Dict(k => v for (k, v) in pairs(_default_switched_shunt) if k != "SWREM"), - Dict( - "SWREG" => 0, - "ID" => "1", - "NAME" => "", - ), -) - const _default_gne_device = Dict( "NTERM" => 1, "NREAL" => 0,