diff --git a/src/pm_io/psse.jl b/src/pm_io/psse.jl index d0e5c15..80d5b2f 100644 --- a/src/pm_io/psse.jl +++ b/src/pm_io/psse.jl @@ -2135,13 +2135,16 @@ function _psse2pm_dcline!(pm_data::Dict, pti_data::Dict, import_all::Bool) sub_data["ac_setpoint_from"] = from_bus["ACSET"] sub_data["ac_setpoint_to"] = to_bus["ACSET"] - # ALOSS, MINLOSS in kW, and BLOSS in kW/A. Divide by a 1000 to transform into MW, and divide by baseMVA to normalize to per-unit. + # ALOSS and MINLOSS are constant losses in kW: /1000 -> MW, /baseMVA -> p.u. + # BLOSS is kW per DC ampere, so its p.u. slope is per p.u. current, not per + # p.u. power: P_loss[MW] = BLOSS * I_A / 1000 with + # I_A = I_pu * 1000 * baseMVA / base_kV, giving P_loss[p.u.] = (BLOSS / base_kV) * I_pu. sub_data["converter_loss_from"] = LinearCurve( - from_bus["BLOSS"] / (1000.0 * baseMVA), + from_bus["BLOSS"] / base_voltage, (from_bus["ALOSS"] + from_bus["MINLOSS"]) / (1000.0 * baseMVA), ) sub_data["converter_loss_to"] = LinearCurve( - to_bus["BLOSS"] / (1000.0 * baseMVA), + to_bus["BLOSS"] / base_voltage, (to_bus["ALOSS"] + to_bus["MINLOSS"]) / (1000.0 * baseMVA), ) diff --git a/test/test_parse_psse.jl b/test/test_parse_psse.jl index 34446cb..312cdb9 100644 --- a/test/test_parse_psse.jl +++ b/test/test_parse_psse.jl @@ -109,6 +109,25 @@ end @test vscline["rated_dc_voltage"] == 150.0 end +@testset "PSSE VSC converter loss: BLOSS is per-unitized on the DC base kV" begin + # BLOSS is kW per DC ampere, so its LinearCurve slope is p.u. power per p.u. current: + # BLOSS / base_kV, not BLOSS / (1000 * baseMVA), which is not even dimensionless. + # ALOSS/MINLOSS are plain kW and do divide by 1000 * baseMVA. Port of + # PowerSystems.jl 11562cc4b. + file = joinpath(@__DIR__, "fixtures", "synthetic_v35_vsc_line.raw") + pm_data = PowerModelsData(file).data + vscline = only(values(pm_data["vscline"])) + + # Both converters carry ALOSS = 1000.0 kW, BLOSS = 1.5 kW/A, MINLOSS = 0.0, on a + # 150 kV DC base (the TYPE 1 terminal's DCSET) and baseMVA = 100.0. + @test vscline["rated_dc_voltage"] == 150.0 + for side in ("converter_loss_from", "converter_loss_to") + curve = vscline[side] + @test IS.get_proportional_term(curve) ≈ 1.5 / 150.0 + @test IS.get_constant_term(curve) ≈ 1000.0 / (1000.0 * 100.0) + end +end + @testset "PSSE ISW area-slack flag" begin file = joinpath(@__DIR__, "fixtures", "v35_area_slack_variants.raw") pm_data = @test_logs(