From a5d009637dc90e2e5d121bd522fb7455bfdc1946 Mon Sep 17 00:00:00 2001 From: lukelowry Date: Fri, 1 May 2026 21:06:10 -0500 Subject: [PATCH 1/2] branch closed parameter and implementation --- .../Model/PhasorDynamics/Branch/Branch.hpp | 1 + .../PhasorDynamics/Branch/BranchData.hpp | 9 ++-- .../PhasorDynamics/Branch/BranchImpl.hpp | 23 ++++++--- GridKit/Model/PhasorDynamics/INPUT_FORMAT.md | 2 +- .../UnitTests/PhasorDynamics/BranchTests.hpp | 50 +++++++++++++++++++ .../PhasorDynamics/runBranchTests.cpp | 1 + 6 files changed, 73 insertions(+), 13 deletions(-) diff --git a/GridKit/Model/PhasorDynamics/Branch/Branch.hpp b/GridKit/Model/PhasorDynamics/Branch/Branch.hpp index 5355b0b8a..6c46d76c2 100644 --- a/GridKit/Model/PhasorDynamics/Branch/Branch.hpp +++ b/GridKit/Model/PhasorDynamics/Branch/Branch.hpp @@ -166,6 +166,7 @@ namespace GridKit RealT X_{0.0}; RealT G_{0.0}; RealT B_{0.0}; + RealT closed_{1.0}; IdxT bus1_id_{0}; IdxT bus2_id_{0}; diff --git a/GridKit/Model/PhasorDynamics/Branch/BranchData.hpp b/GridKit/Model/PhasorDynamics/Branch/BranchData.hpp index 98528c3d1..481b7d632 100644 --- a/GridKit/Model/PhasorDynamics/Branch/BranchData.hpp +++ b/GridKit/Model/PhasorDynamics/Branch/BranchData.hpp @@ -15,10 +15,11 @@ namespace GridKit /// Initial parameters for a branch enum class BranchParameters { - R, ///< Line series resistance - X, ///< Line series reactance - G, ///< Line shunt conductance - B, ///< Line shunt charging + R, ///< Line series resistance + X, ///< Line series reactance + G, ///< Line shunt conductance + B, ///< Line shunt charging + closed, ///< In-service flag (true = closed, default true) }; /// Ports for a branch diff --git a/GridKit/Model/PhasorDynamics/Branch/BranchImpl.hpp b/GridKit/Model/PhasorDynamics/Branch/BranchImpl.hpp index bcb0c268d..1608c4696 100644 --- a/GridKit/Model/PhasorDynamics/Branch/BranchImpl.hpp +++ b/GridKit/Model/PhasorDynamics/Branch/BranchImpl.hpp @@ -155,8 +155,8 @@ namespace GridKit ScalarT Vi1 = wb[1]; ScalarT Ir1 = -(g_ + 0.5 * G_) * Vr1 + (b_ + 0.5 * B_) * Vi1; ScalarT Ii1 = -(b_ + 0.5 * B_) * Vr1 - (g_ + 0.5 * G_) * Vi1; - h[0] = Ir1; - h[1] = Ii1; + h[0] = closed_ * Ir1; + h[1] = closed_ * Ii1; return 0; } @@ -176,8 +176,8 @@ namespace GridKit ScalarT Vi2 = wb[1]; ScalarT Ir1 = g_ * Vr2 - b_ * Vi2; ScalarT Ii1 = b_ * Vr2 + g_ * Vi2; - h[0] = Ir1; - h[1] = Ii1; + h[0] = closed_ * Ir1; + h[1] = closed_ * Ii1; return 0; } @@ -197,8 +197,8 @@ namespace GridKit ScalarT Vi1 = wb[1]; ScalarT Ir2 = g_ * Vr1 - b_ * Vi1; ScalarT Ii2 = b_ * Vr1 + g_ * Vi1; - h[0] = Ir2; - h[1] = Ii2; + h[0] = closed_ * Ir2; + h[1] = closed_ * Ii2; return 0; } @@ -218,8 +218,8 @@ namespace GridKit ScalarT Vi2 = wb[1]; ScalarT Ir2 = -(g_ + 0.5 * G_) * Vr2 + (b_ + 0.5 * B_) * Vi2; ScalarT Ii2 = -(b_ + 0.5 * B_) * Vr2 - (g_ + 0.5 * G_) * Vi2; - h[0] = Ir2; - h[1] = Ii2; + h[0] = closed_ * Ir2; + h[1] = closed_ * Ii2; return 0; } @@ -275,6 +275,13 @@ namespace GridKit B_ = std::get(data.parameters.at(model_data_type::Parameters::B)); } + if (data.parameters.contains(model_data_type::Parameters::closed)) + { + closed_ = std::get(data.parameters.at(model_data_type::Parameters::closed)) + ? RealT{1.0} + : RealT{0.0}; + } + if (data.ports.contains(model_data_type::Ports::bus1)) { bus1_id_ = data.ports.at(model_data_type::Ports::bus1); diff --git a/GridKit/Model/PhasorDynamics/INPUT_FORMAT.md b/GridKit/Model/PhasorDynamics/INPUT_FORMAT.md index ec01498f2..a83f56d44 100644 --- a/GridKit/Model/PhasorDynamics/INPUT_FORMAT.md +++ b/GridKit/Model/PhasorDynamics/INPUT_FORMAT.md @@ -141,7 +141,7 @@ are specified: Device class | Description | Ports | Initialization parameters | Variables available to monitor --------------|------------------------------------------------------|----------------------------------|---------------------------- | ------------------------- - `Branch` | a basic algebraic pi model for a line or transformer | `bus1`, `bus2` | `R`, `X`, `G`, `B` | `ir1`, `ii1`, `im1`, `p1`, `q1`, `ir2`, `ii2`, `im2`, `p2`, `q2` + `Branch` | a basic algebraic pi model for a line or transformer | `bus1`, `bus2` | `R`, `X`, `G`, `B`, `closed` | `ir1`, `ii1`, `im1`, `p1`, `q1`, `ir2`, `ii2`, `im2`, `p2`, `q2` `Load` | a basic static impedence load model | `bus` | `R`, `X` | `p`, `q` `Genrou` | 6th order machine model | `bus`, `pmech`\*, `speed`\*, `efd`\* | `p0`, `q0`, `H`, `D`, `Ra`, `Tdop`, `Tdopp`, `Tqopp`, `Tqop`, `Xd`, `Xdp`, `Xdpp`, `Xq`, `Xqp`, `Xqpp`, `Xl`, `S10`, `S12`, `mva_base` | `ir`, `ii`, `p`, `q`, `delta`, `omega`, `speed` `GenClassical`| the classical machine model | `bus`, `pmech`\*, `speed`\*, `efd`\* | `p0`, `q0`, `H`, `D`, `Ra`, `Xdp`, `mva_base` | `ir`, `ii`, `p`, `q`, `delta`, `omega` diff --git a/tests/UnitTests/PhasorDynamics/BranchTests.hpp b/tests/UnitTests/PhasorDynamics/BranchTests.hpp index 167bce0a7..c7b1cbc54 100644 --- a/tests/UnitTests/PhasorDynamics/BranchTests.hpp +++ b/tests/UnitTests/PhasorDynamics/BranchTests.hpp @@ -120,6 +120,56 @@ namespace GridKit return success.report(__func__); } + TestOutcome openBranch() + { + TestStatus success = true; + + RealT R{2.0}; ///< Branch series resistance + RealT X{4.0}; ///< Branch series reactance + RealT G{0.2}; ///< Branch shunt conductance + RealT B{1.2}; ///< Branch shunt charging + + DependencyTracking::Variable Vr1{10.0}; ///< Bus-1 real voltage + DependencyTracking::Variable Vi1{20.0}; ///< Bus-1 imaginary voltage + DependencyTracking::Variable Vr2{30.0}; ///< Bus-2 real voltage + DependencyTracking::Variable Vi2{40.0}; ///< Bus-2 imaginary voltage + + Vr1.setVariableNumber(0); + Vi1.setVariableNumber(1); + Vr2.setVariableNumber(2); + Vi2.setVariableNumber(3); + + PhasorDynamics::BusInfinite bus1(Vr1, Vi1); + PhasorDynamics::BusInfinite bus2(Vr2, Vi2); + + PhasorDynamics::BranchData data; + data.parameters[PhasorDynamics::BranchParameters::R] = R; + data.parameters[PhasorDynamics::BranchParameters::X] = X; + data.parameters[PhasorDynamics::BranchParameters::G] = G; + data.parameters[PhasorDynamics::BranchParameters::B] = B; + data.parameters[PhasorDynamics::BranchParameters::closed] = false; + + PhasorDynamics::Branch branch(&bus1, &bus2, data); + branch.allocate(); + branch.evaluateResidual(); + + /// Open branch contributes nothing: residual values AND every tracked + /// derivative coefficient must be zero. Verifies the `closed` parse + /// path, the residual mask, and mask propagation through AD in one shot. + const RealT zero{0.0}; + std::vector residuals{bus1.Ir(), bus1.Ii(), bus2.Ir(), bus2.Ii()}; + for (const auto& res : residuals) + { + success *= isEqual(res.getValue(), zero); + for (const auto& [var_id, coef] : res.getDependencies()) + { + success *= isEqual(coef, zero); + } + } + + return success.report(__func__); + } + TestOutcome accessors() { TestStatus success = true; diff --git a/tests/UnitTests/PhasorDynamics/runBranchTests.cpp b/tests/UnitTests/PhasorDynamics/runBranchTests.cpp index 123f5d290..428e2f882 100644 --- a/tests/UnitTests/PhasorDynamics/runBranchTests.cpp +++ b/tests/UnitTests/PhasorDynamics/runBranchTests.cpp @@ -12,6 +12,7 @@ int main() result += test.accessors(); result += test.residual(); result += test.jacobian(); + result += test.openBranch(); return result.summary(); } From 0643a1882d85d71a6dc8a01e013c43695cc346a1 Mon Sep 17 00:00:00 2001 From: lukelowry Date: Fri, 1 May 2026 21:17:03 -0500 Subject: [PATCH 2/2] Update CHANGLELOG for Branch parameter --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8766c4b80..d38584bad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,8 @@ - Added 200 Bus Synthetic Illinois Case - Added node objects to `PowerElectronics` module & updated all examples to make use of them. - Separated internal and external residuals of `PowerElectronics` models. +- Added `closed` parameter to `Branch` for declaring out-of-service lines in case files. + ## v0.1