From ae0563353f9c71a99fed1dd3f687cbbed24523d7 Mon Sep 17 00:00:00 2001 From: superwhiskers Date: Wed, 2 Jul 2025 15:26:46 -0400 Subject: [PATCH 01/16] initial progress on the new data structure parsing approach --- .gitmodules | 3 + CMakeLists.txt | 3 +- .../Tiny/ThreeBus/Basic/ThreeBusBasic.cpp | 11 +- .../Tiny/TwoBus/Basic/TwoBusBasic.cpp | 9 +- .../Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp | 6 +- .../PhasorDynamics/BusFault/BusFault.cpp | 51 ++++++- .../PhasorDynamics/BusFault/BusFault.hpp | 10 +- .../PhasorDynamics/BusFault/BusFaultData.hpp | 142 ++++-------------- src/Model/PhasorDynamics/ComponentData.hpp | 134 +++++++++++++++++ src/Model/PhasorDynamics/SystemModel.hpp | 7 +- src/Model/PhasorDynamics/SystemModelData.hpp | 2 +- .../PhasorDynamics/CaseFormatTests.hpp | 10 +- third-party/magic-enum | 1 + 13 files changed, 240 insertions(+), 149 deletions(-) create mode 100644 src/Model/PhasorDynamics/ComponentData.hpp create mode 160000 third-party/magic-enum diff --git a/.gitmodules b/.gitmodules index 68bbbba7f..5ec1ebf92 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,3 +5,6 @@ [submodule "third-party/nlohmann-json"] path = third-party/nlohmann-json url = https://github.com/nlohmann/json +[submodule "third-party/magic-enum"] + path = third-party/magic-enum + url = https://github.com/Neargye/magic_enum diff --git a/CMakeLists.txt b/CMakeLists.txt index 11acceb4a..c897c5ae3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ set(PACKAGE_VERSION_PATCH "0") set(PACKAGE_VERSION "${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}.${PACKAGE_VERSION_PATCH}") -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) if (MSVC) set(CMAKE_CXX_FLAGS "/Wall") @@ -84,6 +84,7 @@ endif("${isSystemDir}" STREQUAL "-1") include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/third-party/nlohmann-json/single_include) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/third-party/magic-enum/include) option(GRIDKIT_BUILD_SHARED "Build shared libraries" ON) option(GRIDKIT_BUILD_STATIC "Build static libraries" OFF) diff --git a/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp b/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp index be2d1287f..ff2b828f3 100644 --- a/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp +++ b/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp @@ -8,13 +8,12 @@ * compares results with data generated for the same system by Poweworld. * */ -#include "ThreeBusBasic.hpp" - #include #include #include #include +#include "ThreeBusBasic.hpp" #include #include #include @@ -198,10 +197,10 @@ int main() // Set fault data data.bus_fault.resize(1); - data.bus_fault[0].bus_id = 2; - data.bus_fault[0].R = 0.0; - data.bus_fault[0].X = 1e-5; - data.bus_fault[0].status = false; + data.bus_fault[0].ports[BusFaultData::Ports::bus] = 2; + data.bus_fault[0].parameters[BusFaultData::Parameters::R] = 0.0; + data.bus_fault[0].parameters[BusFaultData::Parameters::X] = 1e-5; + data.bus_fault[0].parameters[BusFaultData::Parameters::state0] = false; // // Instantiate system diff --git a/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp b/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp index 55f660363..7c75d1cb6 100644 --- a/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp +++ b/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp @@ -8,11 +8,10 @@ * compares results with data generated for the same system by Poweworld. * */ -#include "TwoBusBasic.hpp" - #include #include +#include "TwoBusBasic.hpp" #include #include #include @@ -92,9 +91,9 @@ int main() // Add faults data.bus_fault.resize(1); - data.bus_fault[0].R = 0.0; - data.bus_fault[0].X = 1e-3; - data.bus_fault[0].status = false; + data.bus_fault[0].parameters[BusFaultData::Parameters::R] = 0.0; + data.bus_fault[0].parameters[BusFaultData::Parameters::X] = 1e-3; + data.bus_fault[0].parameters[BusFaultData::Parameters::state0] = false; // // Instantiate system model diff --git a/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp b/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp index 177964547..c42b7b6c1 100644 --- a/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp +++ b/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp @@ -72,9 +72,9 @@ int main() // Add faults data.bus_fault.resize(1); - data.bus_fault[0].R = 0.0; - data.bus_fault[0].X = 1e-3; - data.bus_fault[0].status = false; + data.bus_fault[0].parameters[BusFaultData::Parameters::R] = 0.0; + data.bus_fault[0].parameters[BusFaultData::Parameters::X] = 1e-3; + data.bus_fault[0].parameters[BusFaultData::Parameters::state0] = false; // // Instantiate system model diff --git a/src/Model/PhasorDynamics/BusFault/BusFault.cpp b/src/Model/PhasorDynamics/BusFault/BusFault.cpp index c14e90b0a..4b249c136 100644 --- a/src/Model/PhasorDynamics/BusFault/BusFault.cpp +++ b/src/Model/PhasorDynamics/BusFault/BusFault.cpp @@ -7,11 +7,10 @@ * */ -#include "BusFault.hpp" - #include #include +#include "BusFault.hpp" #include #include @@ -63,12 +62,50 @@ namespace GridKit */ template BusFault::BusFault(bus_type* bus, const DataT& data) - : bus_(bus), - R_(data.R), - X_(data.X), - status_(data.status), - busID_(data.bus_id) + : bus_(bus) { + if (data.parameters.contains(DataT::Parameters::R)) + { + if (const real_type* R = std::get_if(&data.parameters.at(DataT::Parameters::R))) + { + R_ = *R; + } + else if (const IdxT* R = std::get_if(&data.parameters.at(DataT::Parameters::R))) + { + R_ = static_cast(*R); + } + else + { + throw "Invalid type for R"; + } + } + + if (data.parameters.contains(DataT::Parameters::X)) + { + if (const real_type* X = std::get_if(&data.parameters.at(DataT::Parameters::X))) + { + X_ = *X; + } + else if (const IdxT* X = std::get_if(&data.parameters.at(DataT::Parameters::X))) + { + X_ = static_cast(*X); + } + else + { + throw "Invalid type for X"; + } + } + + if (data.parameters.contains(DataT::Parameters::state0)) + { + status_ = std::get(data.parameters.at(DataT::Parameters::state0)); + } + + if (data.ports.contains(DataT::Ports::bus)) + { + busID_ = data.ports.at(DataT::Ports::bus); + } + size_ = 0; } diff --git a/src/Model/PhasorDynamics/BusFault/BusFault.hpp b/src/Model/PhasorDynamics/BusFault/BusFault.hpp index 9902d33c6..11ec32fb0 100644 --- a/src/Model/PhasorDynamics/BusFault/BusFault.hpp +++ b/src/Model/PhasorDynamics/BusFault/BusFault.hpp @@ -88,11 +88,11 @@ namespace GridKit } private: - bus_type* bus_; - real_type R_; - real_type X_; - bool status_; - const IdxT busID_; + bus_type* bus_; + real_type R_{0.0}; + real_type X_{0.0}; + bool status_{false}; + IdxT busID_{0}; }; } // namespace PhasorDynamics diff --git a/src/Model/PhasorDynamics/BusFault/BusFaultData.hpp b/src/Model/PhasorDynamics/BusFault/BusFaultData.hpp index 43503fb45..47ccca849 100644 --- a/src/Model/PhasorDynamics/BusFault/BusFaultData.hpp +++ b/src/Model/PhasorDynamics/BusFault/BusFaultData.hpp @@ -6,17 +6,33 @@ */ #pragma once -#include -#include -#include -#include - -#include +#include namespace GridKit { namespace PhasorDynamics { + + enum class BusFaultParameters + { + state0, + R, + X, + }; + + enum class BusFaultPorts + { + bus, + control_signal, + }; + + enum class BusFaultMonitorableVariables + { + state, + ir, + ii, + }; + /** * @brief Contains modeling data for a short-to-ground fault * @@ -24,119 +40,15 @@ namespace GridKit * @tparam IdxT Integer parameter data type * * Integer parameters are of the same type as matrix and vector indices. - * - * @todo Decide on naming scheme for model parameters. */ template - struct BusFaultData + struct BusFaultData : public ComponentData { - RealT R{0.0}; ///< Short to ground resistance - RealT X{0.0}; ///< Short to ground reactance - bool status{false}; ///< If the fault has happened + BusFaultData() = default; - std::optional control_signal; ///< Unique ID of the bus providing a control signal - IdxT bus_id{0}; ///< Unique ID of the bus where the fault occurs - - std::optional freq_base; ///< Override for the system-wide base frequency - std::optional va_base; ///< Override for the system-wide power base - - std::string disambiguation_string; ///< Disambiguation string for this device - - /// Indices of the variables able to be monitored in the bitset - enum class MonitorableVariables : size_t - { - STATE, - IR, - II, - MAXIMUM, - }; - - /// Set of variables being monitored - std::bitset>(MonitorableVariables::MAXIMUM)> - monitored_variables; + using Parameters = BusFaultParameters; + using Ports = BusFaultPorts; + using MonitorableVariables = BusFaultMonitorableVariables; }; - - /// JSON parser function implementation for the `BusFaultData` type - /// - /// See the `README.md` in `src/Model/PhasorDynamics` for more information - template - void from_json(const json& j, BusFaultData& bf) - { - for (auto& raw_parameter : j.at("params").items()) - { - if (raw_parameter.key() == "R") - { - raw_parameter.value().get_to(bf.R); - } - else if (raw_parameter.key() == "X") - { - raw_parameter.value().get_to(bf.X); - } - else if (raw_parameter.key() == "state0") - { - raw_parameter.value().get_to(bf.status); - } - else - { - throw "Invalid initial parameter"; - } - } - - for (auto& raw_port : j.at("ports").items()) - { - if (raw_port.key() == "bus") - { - raw_port.value().get_to(bf.bus_id); - } - else if (raw_port.key() == "control_signal") - { - raw_port.value().get_to(bf.control_signal); - } - else - { - throw "Invalid port mapping"; - } - } - - if (j.contains("freq_base")) - { - j.at("freq_base").get_to(bf.freq_base); - } - - if (j.contains("va_base")) - { - j.at("va_base").get_to(bf.va_base); - } - - j.at("id").get_to(bf.disambiguation_string); - - if (j.contains("mon")) - { - for (auto& raw_monitored_variable : j.at("mon")) - { - auto monitored = raw_monitored_variable.get(); - if (monitored == "state") - { - bf.monitored_variables.set(static_cast( - BusFaultData::MonitorableVariables::STATE)); - } - else if (monitored == "ir") - { - bf.monitored_variables.set(static_cast( - BusFaultData::MonitorableVariables::IR)); - } - else if (monitored == "ii") - { - bf.monitored_variables.set(static_cast( - BusFaultData::MonitorableVariables::II)); - } - else - { - throw "Invalid monitored variable"; - } - } - } - } } // namespace PhasorDynamics } // namespace GridKit diff --git a/src/Model/PhasorDynamics/ComponentData.hpp b/src/Model/PhasorDynamics/ComponentData.hpp new file mode 100644 index 000000000..c44a6361b --- /dev/null +++ b/src/Model/PhasorDynamics/ComponentData.hpp @@ -0,0 +1,134 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace GridKit +{ + namespace PhasorDynamics + { + using json = nlohmann::json; + + /** + * @brief Unified interface for `Component` data containers + * + * @tparam RealT Real parameter data type + * @tparam IdxT Integer parameter data type + */ + template + requires std::is_enum_v && std::is_enum_v && std::is_enum_v + struct ComponentData + { + /// Class of device this is for + std::string device_class; + + /// Mapping of parameters to parameter values + std::map> parameters; + + /// Mapping of ports to port values + std::map ports; + + /// Set of variables being monitored + std::set monitored_variables; + + std::optional freq_base; ///< Override for the system-wide base frequency + std::optional va_base; ///< Override for the system-wide power base + + std::string disambiguation_string; ///< Disambiguation string for this device + + protected: + ComponentData() = default; + }; + + /// JSON parser function for the `ComponentData` class and descendants + template + requires std::is_enum_v && std::is_enum_v && std::is_enum_v + void from_json(const json& j, ComponentData& c) + { + j.at("class").get_to(c.device_class); + + for (auto& raw_parameter : j.at("params").items()) + { + auto key = magic_enum::enum_cast(raw_parameter.key()); + if (key.has_value()) + { + //NOTE: this is necessary because it doesn't seem like nlohmann/json handles std::variant + // out of the box + if (raw_parameter.value().is_boolean()) + { + c.parameters[key.value()] = raw_parameter.value().template get(); + } + else if (raw_parameter.value().is_number_float()) + { + c.parameters[key.value()] = raw_parameter.value().template get(); + } + else if (raw_parameter.value().is_number_integer()) + { + c.parameters[key.value()] = raw_parameter.value().template get(); + } + else + { + throw "Invalid initial parameter"; + } + } + else + { + throw "Invalid initial parameter"; + } + } + + for (auto& raw_port : j.at("ports").items()) + { + auto key = magic_enum::enum_cast(raw_port.key()); + if (key.has_value()) + { + raw_port.value().get_to(c.ports[key.value()]); + } + else + { + throw "Invalid port mapping"; + } + } + + if (j.contains("freq_base")) + { + j.at("freq_base").get_to(c.freq_base); + } + + if (j.contains("va_base")) + { + j.at("va_base").get_to(c.va_base); + } + + j.at("id").get_to(c.disambiguation_string); + + if (j.contains("mon")) + { + for (auto& raw_monitored_variable : j.at("mon")) + { + auto monitored = magic_enum::enum_cast(raw_monitored_variable.get()); + if (monitored.has_value()) + { + c.monitored_variables.insert(monitored.value()); + } + else + { + throw "Invalid monitored variable"; + } + } + } + } + } // namespace PhasorDynamics +} // namespace GridKit diff --git a/src/Model/PhasorDynamics/SystemModel.hpp b/src/Model/PhasorDynamics/SystemModel.hpp index 606916657..b8f80efb4 100644 --- a/src/Model/PhasorDynamics/SystemModel.hpp +++ b/src/Model/PhasorDynamics/SystemModel.hpp @@ -120,7 +120,12 @@ namespace GridKit // Add faults for (const auto& faultdata : data.bus_fault) { - auto* fault = new BusFault(getBus(faultdata.bus_id), faultdata); + IdxT bus_index = 0; + if (faultdata.ports.contains(BusFaultData::Ports::bus)) + { + bus_index = faultdata.ports.at(BusFaultData::Ports::bus); + } + auto* fault = new BusFault(getBus(bus_index), faultdata); addFault(fault); } } diff --git a/src/Model/PhasorDynamics/SystemModelData.hpp b/src/Model/PhasorDynamics/SystemModelData.hpp index b58d99b9d..3acdf4e4e 100644 --- a/src/Model/PhasorDynamics/SystemModelData.hpp +++ b/src/Model/PhasorDynamics/SystemModelData.hpp @@ -123,7 +123,7 @@ namespace GridKit else if (kind == "bus_fault") { typename SystemModelData::BusFaultDataT bus_fault; - raw_component.get_to(bus_fault); + raw_component.get_to((bus_fault)); sm.bus_fault.push_back(bus_fault); } else diff --git a/tests/UnitTests/PhasorDynamics/CaseFormatTests.hpp b/tests/UnitTests/PhasorDynamics/CaseFormatTests.hpp index 4a8c3bbac..283690ee0 100644 --- a/tests/UnitTests/PhasorDynamics/CaseFormatTests.hpp +++ b/tests/UnitTests/PhasorDynamics/CaseFormatTests.hpp @@ -111,12 +111,12 @@ namespace GridKit success *= result.genrou[0].monitored_variables[static_cast(SystemModelDataT::GenrouDataT::MonitorableVariables::DELTA)]; success *= result.genrou[0].monitored_variables[static_cast(SystemModelDataT::GenrouDataT::MonitorableVariables::OMEGA)]; - success *= result.bus_fault[0].R == 0.0; - success *= result.bus_fault[0].X == 1e-3; - success *= result.bus_fault[0].status == false; - success *= result.bus_fault[0].bus_id == 1; + success *= std::get(result.bus_fault[0].parameters[SystemModelDataT::BusFaultDataT::Parameters::R]) == 0; + success *= std::get(result.bus_fault[0].parameters[SystemModelDataT::BusFaultDataT::Parameters::X]) == 1e-3; + success *= std::get(result.bus_fault[0].parameters[SystemModelDataT::BusFaultDataT::Parameters::state0]) == false; + success *= result.bus_fault[0].ports[SystemModelDataT::BusFaultDataT::Ports::bus] == 1; success *= result.bus_fault[0].disambiguation_string == "1"; - success *= result.bus_fault[0].monitored_variables.none(); + success *= result.bus_fault[0].monitored_variables.empty(); return success.report(__func__); } diff --git a/third-party/magic-enum b/third-party/magic-enum new file mode 160000 index 000000000..ecdeb1cea --- /dev/null +++ b/third-party/magic-enum @@ -0,0 +1 @@ +Subproject commit ecdeb1cea54d87b09bafe9999faf56654646209d From 6109ddf65289da6cd5bbaac4356a1d4f45053ead Mon Sep 17 00:00:00 2001 From: superwhiskers Date: Wed, 2 Jul 2025 19:30:49 +0000 Subject: [PATCH 02/16] Apply pre-commmit fixes --- examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp | 3 ++- examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp | 3 ++- src/Model/PhasorDynamics/BusFault/BusFault.cpp | 3 ++- src/Model/PhasorDynamics/ComponentData.hpp | 4 ++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp b/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp index ff2b828f3..dea79505a 100644 --- a/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp +++ b/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp @@ -8,12 +8,13 @@ * compares results with data generated for the same system by Poweworld. * */ +#include "ThreeBusBasic.hpp" + #include #include #include #include -#include "ThreeBusBasic.hpp" #include #include #include diff --git a/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp b/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp index 7c75d1cb6..b3cb7467d 100644 --- a/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp +++ b/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp @@ -8,10 +8,11 @@ * compares results with data generated for the same system by Poweworld. * */ +#include "TwoBusBasic.hpp" + #include #include -#include "TwoBusBasic.hpp" #include #include #include diff --git a/src/Model/PhasorDynamics/BusFault/BusFault.cpp b/src/Model/PhasorDynamics/BusFault/BusFault.cpp index 4b249c136..fcef32089 100644 --- a/src/Model/PhasorDynamics/BusFault/BusFault.cpp +++ b/src/Model/PhasorDynamics/BusFault/BusFault.cpp @@ -7,10 +7,11 @@ * */ +#include "BusFault.hpp" + #include #include -#include "BusFault.hpp" #include #include diff --git a/src/Model/PhasorDynamics/ComponentData.hpp b/src/Model/PhasorDynamics/ComponentData.hpp index c44a6361b..6abbc7201 100644 --- a/src/Model/PhasorDynamics/ComponentData.hpp +++ b/src/Model/PhasorDynamics/ComponentData.hpp @@ -64,8 +64,8 @@ namespace GridKit auto key = magic_enum::enum_cast(raw_parameter.key()); if (key.has_value()) { - //NOTE: this is necessary because it doesn't seem like nlohmann/json handles std::variant - // out of the box + // NOTE: this is necessary because it doesn't seem like nlohmann/json handles std::variant + // out of the box if (raw_parameter.value().is_boolean()) { c.parameters[key.value()] = raw_parameter.value().template get(); From e20c2438eac351b80769d39e87704e6e069708fc Mon Sep 17 00:00:00 2001 From: superwhiskers Date: Thu, 3 Jul 2025 08:23:12 -0400 Subject: [PATCH 03/16] move the case format tests and require floating point parameters to be floating point literals again. no implicit conversions --- .../PhasorDynamics/BusFault/BusFault.cpp | 26 +----------- src/Model/PhasorDynamics/INPUT_FORMAT.md | 12 +++--- tests/UnitTests/CMakeLists.txt | 1 + tests/UnitTests/PhasorDynamics/CMakeLists.txt | 4 -- tests/UnitTests/Utilities/CMakeLists.txt | 5 +++ .../CaseFormatTests.hpp | 42 +++++++++---------- .../runCaseFormatTests.cpp | 0 7 files changed, 35 insertions(+), 55 deletions(-) create mode 100644 tests/UnitTests/Utilities/CMakeLists.txt rename tests/UnitTests/{PhasorDynamics => Utilities}/CaseFormatTests.hpp (74%) rename tests/UnitTests/{PhasorDynamics => Utilities}/runCaseFormatTests.cpp (100%) diff --git a/src/Model/PhasorDynamics/BusFault/BusFault.cpp b/src/Model/PhasorDynamics/BusFault/BusFault.cpp index fcef32089..1eabbb862 100644 --- a/src/Model/PhasorDynamics/BusFault/BusFault.cpp +++ b/src/Model/PhasorDynamics/BusFault/BusFault.cpp @@ -67,34 +67,12 @@ namespace GridKit { if (data.parameters.contains(DataT::Parameters::R)) { - if (const real_type* R = std::get_if(&data.parameters.at(DataT::Parameters::R))) - { - R_ = *R; - } - else if (const IdxT* R = std::get_if(&data.parameters.at(DataT::Parameters::R))) - { - R_ = static_cast(*R); - } - else - { - throw "Invalid type for R"; - } + R_ = std::get(data.parameters.at(DataT::Parameters::R)); } if (data.parameters.contains(DataT::Parameters::X)) { - if (const real_type* X = std::get_if(&data.parameters.at(DataT::Parameters::X))) - { - X_ = *X; - } - else if (const IdxT* X = std::get_if(&data.parameters.at(DataT::Parameters::X))) - { - X_ = static_cast(*X); - } - else - { - throw "Invalid type for X"; - } + X_ = std::get(data.parameters.at(DataT::Parameters::X)); } if (data.parameters.contains(DataT::Parameters::state0)) diff --git a/src/Model/PhasorDynamics/INPUT_FORMAT.md b/src/Model/PhasorDynamics/INPUT_FORMAT.md index 775364d69..905fa983f 100644 --- a/src/Model/PhasorDynamics/INPUT_FORMAT.md +++ b/src/Model/PhasorDynamics/INPUT_FORMAT.md @@ -129,18 +129,18 @@ connected to a constant value. This list is subject to change. "case_name": "Two-bus test case 1", "case_description": "A two-bus test case for demonstrating the dynamics format", "case_comments": "This case is set up to monitor the voltage at both buses and the machine angle and speed", - "freq_base": 60, + "freq_base": 60.0, "va_base": 100e6 }, "buses": [ { "number": 1, "class": "bus", "name": "Bus 1", "init": {"Vr":0.994988, "Vi":0.099997}, "v_base": 115e3, "mon": ["Vr", "Vi"] }, - { "number": 2, "class": "infinite_bus", "name": "Bus 2", "init": {"Vr":1, "Vi":0}, "v_base": 115e3 } + { "number": 2, "class": "infinite_bus", "name": "Bus 2", "init": {"Vr":1.0, "Vi":0.0}, "v_base": 115e3 } ], "devices": [ - { "class": "branch", "ports": {"bus1":1, "bus2":2}, "id": "1", "params": {"R":0, "X":0.1, "G":0, "B":0} }, - { "class": "GENROU", "ports": {"bus":1}, "id": "1", "params": {"p0":1, "q0":0.05013, "H":3, "D":0, "Ra":0, "Tdop":7, "Tdopp":0.04, "Tqopp":0.05, - "Tqop":0.75, "Xd":2.1, "Xdp":0.2, "Xdpp":0.18, "Xq":0.5, "Xqp": 0, "Xqpp":0.18, "Xl":0.15, "S10":0, "S12":0}, "mon": ["delta", "omega"] }, - { "class": "bus_fault", "ports": {"bus":1}, "id": "1", "params": {"state0": false, "R":0, "X":1e-3} } + { "class": "branch", "ports": {"bus1":1, "bus2":2}, "id": "1", "params": {"R":0.0, "X":0.1, "G":0.0, "B":0.0} }, + { "class": "GENROU", "ports": {"bus":1}, "id": "1", "params": {"p0":1.0, "q0":0.05013, "H":3.0, "D":0.0, "Ra":0.0, "Tdop":7.0, "Tdopp":0.04, "Tqopp":0.05, + "Tqop":0.75, "Xd":2.1, "Xdp":0.2, "Xdpp":0.18, "Xq":0.5, "Xqp": 0.0, "Xqpp":0.18, "Xl":0.15, "S10":0.0, "S12":0.0}, "mon": ["delta", "omega"] }, + { "class": "bus_fault", "ports": {"bus":1}, "id": "1", "params": {"state0": false, "R":0.0, "X":1e-3} } ] } ``` diff --git a/tests/UnitTests/CMakeLists.txt b/tests/UnitTests/CMakeLists.txt index a168f9f7d..38c12eeee 100644 --- a/tests/UnitTests/CMakeLists.txt +++ b/tests/UnitTests/CMakeLists.txt @@ -2,3 +2,4 @@ add_subdirectory(AutomaticDifferentiation) add_subdirectory(PhasorDynamics) add_subdirectory(Solver) +add_subdirectory(Utilities) diff --git a/tests/UnitTests/PhasorDynamics/CMakeLists.txt b/tests/UnitTests/PhasorDynamics/CMakeLists.txt index 170e86db1..43e824dcb 100644 --- a/tests/UnitTests/PhasorDynamics/CMakeLists.txt +++ b/tests/UnitTests/PhasorDynamics/CMakeLists.txt @@ -11,8 +11,6 @@ add_executable(test_phasor_branch runBranchTests.cpp) target_link_libraries(test_phasor_branch GRIDKIT::phasor_dynamics_branch GRIDKIT::phasor_dynamics_bus) -add_executable(test_case_format runCaseFormatTests.cpp) - add_executable(test_phasor_load runLoadTests.cpp) target_link_libraries(test_phasor_load GRIDKIT::phasor_dynamics_load GRIDKIT::phasor_dynamics_load_dependency_tracking @@ -42,7 +40,6 @@ target_link_libraries(test_phasor_system GRIDKIT::phasor_dynamics_load add_test(NAME PhasorDynamicsBusTest COMMAND $) add_test(NAME PhasorDynamicsBranchTest COMMAND $) -add_test(NAME PhasorDynamicsCaseFormatTest COMMAND $) add_test(NAME PhasorDynamicsGenrouTest COMMAND $) add_test(NAME PhasorDynamicsGovernorTgov1Test COMMAND $) add_test(NAME PhasorDynamicsGenClassicalTest COMMAND $) @@ -51,7 +48,6 @@ add_test(NAME PhasorDynamicsSystemTest COMMAND $ install(TARGETS test_phasor_bus test_phasor_branch - test_case_format test_phasor_load test_phasor_genrou test_phasor_governortgov1 diff --git a/tests/UnitTests/Utilities/CMakeLists.txt b/tests/UnitTests/Utilities/CMakeLists.txt new file mode 100644 index 000000000..d1c337fc1 --- /dev/null +++ b/tests/UnitTests/Utilities/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(test_case_format runCaseFormatTests.cpp) + +add_test(NAME UtilitiesCaseFormatTest COMMAND $) + +install(TARGETS test_case_format) diff --git a/tests/UnitTests/PhasorDynamics/CaseFormatTests.hpp b/tests/UnitTests/Utilities/CaseFormatTests.hpp similarity index 74% rename from tests/UnitTests/PhasorDynamics/CaseFormatTests.hpp rename to tests/UnitTests/Utilities/CaseFormatTests.hpp index 283690ee0..063cf5483 100644 --- a/tests/UnitTests/PhasorDynamics/CaseFormatTests.hpp +++ b/tests/UnitTests/Utilities/CaseFormatTests.hpp @@ -24,26 +24,26 @@ namespace GridKit { const char data[] = R"({ - "header": { - "format_version": 0, - "format_revision": 1, - "case_name": "Two-bus test case 1", - "case_description": "A two-bus test case for demonstrating the dynamics format", - "case_comments": "This case is set up to monitor the voltage at both buses and the machine angle and speed", - "freq_base": 60, - "va_base": 100e6 - }, - "buses": [ - { "number": 1, "class": "bus", "name": "Bus 1", "init": {"Vr":0.994988, "Vi":0.099997}, "v_base": 115e3, "mon": ["Vr", "Vi"] }, - { "number": 2, "class": "infinite_bus", "name": "Bus 2", "init": {"Vr":1, "Vi":0}, "v_base": 115e3 } - ], - "devices": [ - { "class": "branch", "ports": {"bus1":1, "bus2":2}, "id": "1", "params": {"R":0, "X":0.1, "G":0, "B":0} }, - { "class": "GENROU", "ports": {"bus":1}, "id": "1", "params": {"p0":1, "q0":0.05013, "H":3, "D":0, "Ra":0, "Tdop":7, "Tdopp":0.04, "Tqopp":0.05, - "Tqop":0.75, "Xd":2.1, "Xdp":0.2, "Xdpp":0.18, "Xq":0.5, "Xqp": 0, "Xqpp":0.18, "Xl":0.15, "S10":0, "S12":0}, "mon": ["delta", "omega"] }, - { "class": "bus_fault", "ports": {"bus":1}, "id": "1", "params": {"state0": false, "R":0, "X":1e-3} } - ] - })"; + "header": { + "format_version": 0, + "format_revision": 1, + "case_name": "Two-bus test case 1", + "case_description": "A two-bus test case for demonstrating the dynamics format", + "case_comments": "This case is set up to monitor the voltage at both buses and the machine angle and speed", + "freq_base": 60.0, + "va_base": 100e6 + }, + "buses": [ + { "number": 1, "class": "bus", "name": "Bus 1", "init": {"Vr":0.994988, "Vi":0.099997}, "v_base": 115e3, "mon": ["Vr", "Vi"] }, + { "number": 2, "class": "infinite_bus", "name": "Bus 2", "init": {"Vr":1.0, "Vi":0.0}, "v_base": 115e3 } + ], + "devices": [ + { "class": "branch", "ports": {"bus1":1, "bus2":2}, "id": "1", "params": {"R":0.0, "X":0.1, "G":0.0, "B":0.0} }, + { "class": "GENROU", "ports": {"bus":1}, "id": "1", "params": {"p0":1.0, "q0":0.05013, "H":3.0, "D":0.0, "Ra":0.0, "Tdop":7.0, "Tdopp":0.04, "Tqopp":0.05, + "Tqop":0.75, "Xd":2.1, "Xdp":0.2, "Xdpp":0.18, "Xq":0.5, "Xqp": 0.0, "Xqpp":0.18, "Xl":0.15, "S10":0.0, "S12":0.0}, "mon": ["delta", "omega"] }, + { "class": "bus_fault", "ports": {"bus":1}, "id": "1", "params": {"state0": false, "R":0.0, "X":1e-3} } + ] + })"; TestStatus success = true; SystemModelDataT result = json::parse(data); @@ -111,7 +111,7 @@ namespace GridKit success *= result.genrou[0].monitored_variables[static_cast(SystemModelDataT::GenrouDataT::MonitorableVariables::DELTA)]; success *= result.genrou[0].monitored_variables[static_cast(SystemModelDataT::GenrouDataT::MonitorableVariables::OMEGA)]; - success *= std::get(result.bus_fault[0].parameters[SystemModelDataT::BusFaultDataT::Parameters::R]) == 0; + success *= std::get(result.bus_fault[0].parameters[SystemModelDataT::BusFaultDataT::Parameters::R]) == 0.0; success *= std::get(result.bus_fault[0].parameters[SystemModelDataT::BusFaultDataT::Parameters::X]) == 1e-3; success *= std::get(result.bus_fault[0].parameters[SystemModelDataT::BusFaultDataT::Parameters::state0]) == false; success *= result.bus_fault[0].ports[SystemModelDataT::BusFaultDataT::Ports::bus] == 1; diff --git a/tests/UnitTests/PhasorDynamics/runCaseFormatTests.cpp b/tests/UnitTests/Utilities/runCaseFormatTests.cpp similarity index 100% rename from tests/UnitTests/PhasorDynamics/runCaseFormatTests.cpp rename to tests/UnitTests/Utilities/runCaseFormatTests.cpp From 914199bf0595f0fc68d1509a5ea954f0bb04c662 Mon Sep 17 00:00:00 2001 From: superwhiskers Date: Thu, 3 Jul 2025 08:31:10 -0400 Subject: [PATCH 04/16] add some documentation to the modified bus fault data structure --- src/Model/PhasorDynamics/BusFault/BusFaultData.hpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Model/PhasorDynamics/BusFault/BusFaultData.hpp b/src/Model/PhasorDynamics/BusFault/BusFaultData.hpp index 47ccca849..39cfc811b 100644 --- a/src/Model/PhasorDynamics/BusFault/BusFaultData.hpp +++ b/src/Model/PhasorDynamics/BusFault/BusFaultData.hpp @@ -12,20 +12,30 @@ namespace GridKit { namespace PhasorDynamics { - + /// Initial parameters for a bus fault enum class BusFaultParameters { + /// Whether or not the fault has happened state0, + + /// Short to ground resistance R, + + /// Short to ground reactance X, }; + /// Ports supported for a bus fault enum class BusFaultPorts { + /// Unique ID of the bus where the fault occurs bus, + + /// Unique ID of the bus providing a control signal control_signal, }; + /// Variables able to be monitored for a bus fault enum class BusFaultMonitorableVariables { state, From 4e2710c90e4448fc8f5a6a78232e62b909fe66e0 Mon Sep 17 00:00:00 2001 From: superwhiskers Date: Thu, 3 Jul 2025 13:53:29 -0400 Subject: [PATCH 05/16] break out the component data json parser into a separate file --- src/Model/PhasorDynamics/ComponentData.hpp | 98 ++----------------- .../ComponentDataJSONParser.hpp | 98 +++++++++++++++++++ tests/UnitTests/Utilities/CaseFormatTests.hpp | 1 + 3 files changed, 107 insertions(+), 90 deletions(-) create mode 100644 src/Model/PhasorDynamics/ComponentDataJSONParser.hpp diff --git a/src/Model/PhasorDynamics/ComponentData.hpp b/src/Model/PhasorDynamics/ComponentData.hpp index 6abbc7201..36e89de9a 100644 --- a/src/Model/PhasorDynamics/ComponentData.hpp +++ b/src/Model/PhasorDynamics/ComponentData.hpp @@ -8,23 +8,24 @@ #include #include -#include -#include - namespace GridKit { namespace PhasorDynamics { - using json = nlohmann::json; - /** * @brief Unified interface for `Component` data containers * * @tparam RealT Real parameter data type * @tparam IdxT Integer parameter data type */ - template - requires std::is_enum_v && std::is_enum_v && std::is_enum_v + template + requires std::is_enum_v + && std::is_enum_v + && std::is_enum_v struct ComponentData { /// Class of device this is for @@ -47,88 +48,5 @@ namespace GridKit protected: ComponentData() = default; }; - - /// JSON parser function for the `ComponentData` class and descendants - template - requires std::is_enum_v && std::is_enum_v && std::is_enum_v - void from_json(const json& j, ComponentData& c) - { - j.at("class").get_to(c.device_class); - - for (auto& raw_parameter : j.at("params").items()) - { - auto key = magic_enum::enum_cast(raw_parameter.key()); - if (key.has_value()) - { - // NOTE: this is necessary because it doesn't seem like nlohmann/json handles std::variant - // out of the box - if (raw_parameter.value().is_boolean()) - { - c.parameters[key.value()] = raw_parameter.value().template get(); - } - else if (raw_parameter.value().is_number_float()) - { - c.parameters[key.value()] = raw_parameter.value().template get(); - } - else if (raw_parameter.value().is_number_integer()) - { - c.parameters[key.value()] = raw_parameter.value().template get(); - } - else - { - throw "Invalid initial parameter"; - } - } - else - { - throw "Invalid initial parameter"; - } - } - - for (auto& raw_port : j.at("ports").items()) - { - auto key = magic_enum::enum_cast(raw_port.key()); - if (key.has_value()) - { - raw_port.value().get_to(c.ports[key.value()]); - } - else - { - throw "Invalid port mapping"; - } - } - - if (j.contains("freq_base")) - { - j.at("freq_base").get_to(c.freq_base); - } - - if (j.contains("va_base")) - { - j.at("va_base").get_to(c.va_base); - } - - j.at("id").get_to(c.disambiguation_string); - - if (j.contains("mon")) - { - for (auto& raw_monitored_variable : j.at("mon")) - { - auto monitored = magic_enum::enum_cast(raw_monitored_variable.get()); - if (monitored.has_value()) - { - c.monitored_variables.insert(monitored.value()); - } - else - { - throw "Invalid monitored variable"; - } - } - } - } } // namespace PhasorDynamics } // namespace GridKit diff --git a/src/Model/PhasorDynamics/ComponentDataJSONParser.hpp b/src/Model/PhasorDynamics/ComponentDataJSONParser.hpp new file mode 100644 index 000000000..4a80676c4 --- /dev/null +++ b/src/Model/PhasorDynamics/ComponentDataJSONParser.hpp @@ -0,0 +1,98 @@ +#pragma once + +#include +#include +#include + +namespace GridKit +{ + namespace PhasorDynamics + { + using json = nlohmann::json; + + /// JSON parser function for the `ComponentData` class and descendants + template + requires std::is_enum_v + && std::is_enum_v + && std::is_enum_v + void from_json(const json& j, ComponentData& c) + { + j.at("class").get_to(c.device_class); + + for (auto& raw_parameter : j.at("params").items()) + { + auto key = magic_enum::enum_cast(raw_parameter.key()); + if (key.has_value()) + { + // NOTE: this is necessary because it doesn't seem like nlohmann/json handles std::variant + // out of the box + if (raw_parameter.value().is_boolean()) + { + c.parameters[key.value()] = raw_parameter.value().template get(); + } + else if (raw_parameter.value().is_number_float()) + { + c.parameters[key.value()] = raw_parameter.value().template get(); + } + else if (raw_parameter.value().is_number_integer()) + { + c.parameters[key.value()] = raw_parameter.value().template get(); + } + else + { + throw "Invalid initial parameter"; + } + } + else + { + throw "Invalid initial parameter"; + } + } + + for (auto& raw_port : j.at("ports").items()) + { + auto key = magic_enum::enum_cast(raw_port.key()); + if (key.has_value()) + { + raw_port.value().get_to(c.ports[key.value()]); + } + else + { + throw "Invalid port mapping"; + } + } + + if (j.contains("freq_base")) + { + j.at("freq_base").get_to(c.freq_base); + } + + if (j.contains("va_base")) + { + j.at("va_base").get_to(c.va_base); + } + + j.at("id").get_to(c.disambiguation_string); + + if (j.contains("mon")) + { + for (auto& raw_monitored_variable : j.at("mon")) + { + auto monitored = magic_enum::enum_cast(raw_monitored_variable.get()); + if (monitored.has_value()) + { + c.monitored_variables.insert(monitored.value()); + } + else + { + throw "Invalid monitored variable"; + } + } + } + } + } // namespace PhasorDynamics +} // namespace GridKit diff --git a/tests/UnitTests/Utilities/CaseFormatTests.hpp b/tests/UnitTests/Utilities/CaseFormatTests.hpp index 063cf5483..4660d4634 100644 --- a/tests/UnitTests/Utilities/CaseFormatTests.hpp +++ b/tests/UnitTests/Utilities/CaseFormatTests.hpp @@ -1,5 +1,6 @@ #include +#include #include #include #include From 8f300688edb5949db77c67d64de179c778e1fb52 Mon Sep 17 00:00:00 2001 From: superwhiskers Date: Tue, 8 Jul 2025 09:19:53 -0400 Subject: [PATCH 06/16] finish reworking the remainder of the applicable `*Data` structures to use `ComponentData` note that this doesn't build due to code relying upon the presence of fields. this will be finished in a subsequent commit --- .../PhasorDynamics/Branch/BranchData.hpp | 213 +++--------- .../PhasorDynamics/BusFault/BusFaultData.hpp | 6 +- src/Model/PhasorDynamics/Load/LoadData.hpp | 50 ++- .../GENROUwS/GenrouData.hpp | 307 ++++++------------ 4 files changed, 182 insertions(+), 394 deletions(-) diff --git a/src/Model/PhasorDynamics/Branch/BranchData.hpp b/src/Model/PhasorDynamics/Branch/BranchData.hpp index 2d6a1d21a..188eff337 100644 --- a/src/Model/PhasorDynamics/Branch/BranchData.hpp +++ b/src/Model/PhasorDynamics/Branch/BranchData.hpp @@ -6,18 +6,52 @@ */ #pragma once -#include -#include -#include -#include - -#include +#include namespace GridKit { namespace PhasorDynamics { - using json = nlohmann::json; + /// Initial parameters for a branch + enum class BranchParameters + { + /// Line series resistance + R, + + /// Line series reactance + X, + + /// Line shunt conductance + G, + + /// Line shunt charging + B, + }; + + /// Ports for a branch + enum class BranchPorts + { + /// Unique ID of bus 1 + bus1, + + /// Unique ID of bus 2 + bus2, + }; + + /// Variables able to be monitored for a branch + enum class BranchMonitorableVariables + { + ir1, + ii1, + im1, + p1, + q1, + ir2, + ii2, + im2, + p2, + q2, + }; /** * @brief Contains modeling data for a Branch @@ -26,166 +60,19 @@ namespace GridKit * @tparam IdxT Integer parameter data type * * Integer parameters are of the same type as matrix and vector indices. - * - * @todo Decide on naming scheme for model parameters. */ template - struct BranchData + struct BranchData : public ComponentData { - RealT R{0.0}; ///< Line series resistance - RealT X{0.0}; ///< Line series reactance - RealT G{0.0}; ///< Line shunt conductance - RealT B{0.0}; ///< Line shunt charging - - IdxT bus1_id{0}; ///< Unique ID of bus 1 - IdxT bus2_id{0}; ///< Unique ID of bus 2 - - std::optional freq_base; ///< Override for the system-wide base frequency - std::optional va_base; ///< Override for the system-wide power base - - std::string disambiguation_string; ///< Disambiguation string for this device + BranchData() = default; - /// Indices of the variables able to be monitored in the bitset - enum class MonitorableVariables : size_t - { - IR1, - II1, - IM1, - P1, - Q1, - IR2, - II2, - IM2, - P2, - Q2, - MAXIMUM, - }; - - /// Set indicating the variables being monitored - std::bitset>(MonitorableVariables::MAXIMUM)> - monitored_variables; + using Parameters = BranchParameters; + using Ports = BranchPorts; + using MonitorableVariables = BranchMonitorableVariables; }; - - /// JSON parser function implementation for the `BranchData` type - /// - /// See the `README.md` in `src/Model/PhasorDynamics` for more information - template - void from_json(const json& j, BranchData& bd) - { - for (auto& raw_parameter : j.at("params").items()) - { - if (raw_parameter.key() == "R") - { - raw_parameter.value().get_to(bd.R); - } - else if (raw_parameter.key() == "X") - { - raw_parameter.value().get_to(bd.X); - } - else if (raw_parameter.key() == "G") - { - raw_parameter.value().get_to(bd.G); - } - else if (raw_parameter.key() == "B") - { - raw_parameter.value().get_to(bd.B); - } - else - { - throw "Invalid initial parameter"; - } - } - - for (auto& raw_port : j.at("ports").items()) - { - if (raw_port.key() == "bus1") - { - raw_port.value().get_to(bd.bus1_id); - } - else if (raw_port.key() == "bus2") - { - raw_port.value().get_to(bd.bus2_id); - } - else - { - throw "Invalid port mapping"; - } - } - - if (j.contains("freq_base")) - { - j.at("freq_base").get_to(bd.freq_base); - } - - if (j.contains("va_base")) - { - j.at("va_base").get_to(bd.va_base); - } - - j.at("id").get_to(bd.disambiguation_string); - - if (j.contains("mon")) - { - for (auto& raw_monitored_variable : j.at("mon")) - { - auto monitored = raw_monitored_variable.get(); - if (monitored == "ir1") - { - bd.monitored_variables.set(static_cast( - BranchData::MonitorableVariables::IR1)); - } - else if (monitored == "ii1") - { - bd.monitored_variables.set(static_cast( - BranchData::MonitorableVariables::II1)); - } - else if (monitored == "im1") - { - bd.monitored_variables.set(static_cast( - BranchData::MonitorableVariables::IM1)); - } - else if (monitored == "p1") - { - bd.monitored_variables.set(static_cast( - BranchData::MonitorableVariables::P1)); - } - else if (monitored == "q1") - { - bd.monitored_variables.set(static_cast( - BranchData::MonitorableVariables::Q1)); - } - else if (monitored == "ir2") - { - bd.monitored_variables.set(static_cast( - BranchData::MonitorableVariables::IR2)); - } - else if (monitored == "ii2") - { - bd.monitored_variables.set(static_cast( - BranchData::MonitorableVariables::II2)); - } - else if (monitored == "im2") - { - bd.monitored_variables.set(static_cast( - BranchData::MonitorableVariables::IM2)); - } - else if (monitored == "p2") - { - bd.monitored_variables.set(static_cast( - BranchData::MonitorableVariables::P2)); - } - else if (monitored == "q2") - { - bd.monitored_variables.set(static_cast( - BranchData::MonitorableVariables::Q2)); - } - else - { - throw "Invalid monitored variable"; - } - } - } - } } // namespace PhasorDynamics } // namespace GridKit diff --git a/src/Model/PhasorDynamics/BusFault/BusFaultData.hpp b/src/Model/PhasorDynamics/BusFault/BusFaultData.hpp index 39cfc811b..58649d6fc 100644 --- a/src/Model/PhasorDynamics/BusFault/BusFaultData.hpp +++ b/src/Model/PhasorDynamics/BusFault/BusFaultData.hpp @@ -52,7 +52,11 @@ namespace GridKit * Integer parameters are of the same type as matrix and vector indices. */ template - struct BusFaultData : public ComponentData + struct BusFaultData : public ComponentData { BusFaultData() = default; diff --git a/src/Model/PhasorDynamics/Load/LoadData.hpp b/src/Model/PhasorDynamics/Load/LoadData.hpp index d5c0d3ebf..e15b6e991 100644 --- a/src/Model/PhasorDynamics/Load/LoadData.hpp +++ b/src/Model/PhasorDynamics/Load/LoadData.hpp @@ -6,37 +6,55 @@ */ #pragma once -#include -#include +#include namespace GridKit { namespace PhasorDynamics { + /// Initial parameters for a load + enum class LoadParameters + { + /// Load resistance + R, + + /// Load reactance + X, + }; + + /// Ports for a load + enum class LoadPorts + { + /// Unique ID of the bus to which the load is connected + bus, + }; + + /// Variables able to be monitored for a load + enum class LoadMonitorableVariables + { + // TODO: presumably some variables would make sense to monitor here + }; + /** - * @brief Contains modeling data for a Load + * @brief Contains modeling data for a load * * @tparam RealT Real parameter data type * @tparam IdxT Integer parameter data type * * Integer parameters are of the same type as matrix and vector indices. - * - * @todo Decide on naming scheme for model parameters. */ template - struct LoadData + struct LoadData : public ComponentData { - RealT R{0.0}; ///< Load resistance - RealT X{0.0}; ///< Load reactance - - IdxT bus_id{0}; ///< Unique ID of bus to which the load is connnected - - std::optional freq_base; ///< Override for the system-wide base frequency - std::optional va_base; ///< Override for the system-wide power base - - std::string disambiguation_string; ///< Disambiguation string for this device + LoadData() = default; - // TODO: add the monitorable variables to this + using Parameters = LoadParameters; + using Ports = LoadPorts; + using MonitorableVariables = LoadMonitorableVariables; }; } // namespace PhasorDynamics } // namespace GridKit diff --git a/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/GenrouData.hpp b/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/GenrouData.hpp index f7836f87f..8300f1049 100644 --- a/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/GenrouData.hpp +++ b/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/GenrouData.hpp @@ -6,17 +6,94 @@ */ #pragma once -#include -#include -#include -#include - -#include +#include namespace GridKit { namespace PhasorDynamics { + /// Initial parameters for a Genrou generator model + enum class GenrouParameters + { + /// Initial active power + p0, + + /// Initial reactive power + q0, + + /// Rotor inertia + H, + + /// Damping coefficient + D, + + /// Winding resistance + Ra, + + /// Open circuit direct axis transient time + Tdop, + + /// Open circuit direct axis sub-transient time + Tdopp, + + /// Open circuit quadrature axis transient + Tqop, + + /// Open circuit quadrature axis sub-transient time + Tqopp, + + /// Direct axis synchronous reactance + Xd, + + /// Direct axis transient reactance + Xdp, + + /// Direct axis sub-transient reactance + Xdpp, + + /// Quadrature axis synchronous reactance + Xq, + + /// Quadrature axis transient reactance + Xqp, + + /// Quadrature axis sub-transient reactance + Xqpp, + + /// Stator leakage reactance + Xl, + + /// Saturation factor at 1.0 pu flux + S10, + + /// Saturation factor at 1.2 pu flux + S12, + }; + + /// Ports for a Genrou generator model + enum class GenrouPorts + { + /// Unique ID of the connecting bus + bus, + + /// Unique ID of the bus providing the exciter signal + exciter_signal, + + /// Unique ID of the bus providing the governor signal + governor_signal, + }; + + /// Variables able to be monitored for a Genrou generator model + enum class GenrouMonitorableVariables + { + ir, + ii, + p, + q, + delta, + omega, + }; + /** * @brief Contains modeling data for a Genrou generator model. * @@ -24,217 +101,19 @@ namespace GridKit * @tparam IdxT Integer parameter data type * * Integer parameters are of the same type as matrix and vector indices. - * - * @todo Decide on naming scheme for model parameters. */ template - struct GenrouData + struct GenrouData : public ComponentData { - RealT p0{0.0}; ///< Initial active power - RealT q0{0.0}; ///< Initial reactive power - RealT H{0.0}; ///< Rotor inertia - RealT D{0.0}; ///< Damping coefficient - RealT Ra{0.0}; ///< Winding resistance - RealT Tdop{0.0}; ///< Open circuit direct axis transient time - RealT Tdopp{0.0}; ///< Open circuit direct axis sub-transient time - RealT Tqop{0.0}; ///< Open circuit quadrature axis transient - RealT Tqopp{0.0}; ///< Open circuit quadrature axis sub-transient time - RealT Xd{0.0}; ///< Direct axis synchronous reactance - RealT Xdp{0.0}; ///< Direct axis transient reactance - RealT Xdpp{0.0}; ///< Direct axis sub-transient reactance - RealT Xq{0.0}; ///< Quadrature axis synchronous reactance - RealT Xqp{0.0}; ///< Quadrature axis transient reactance - RealT Xqpp{0.0}; ///< Quadrature axis sub-transient reactance - RealT Xl{0.0}; ///< Stator leakage reactance - RealT S10{0.0}; ///< Saturation factor at 1.0 pu flux - RealT S12{0.0}; ///< Saturation factor at 1.2 pu flux - - IdxT bus_id{0}; ///< Unique ID of the connecting bus - std::optional exciter_signal; ///< Unique ID of the bus providing the exciter signal - std::optional governor_signal; ///< Unique ID of the bus providing the governor signal - - std::optional freq_base; ///< Override for the system-wide base frequency - std::optional va_base; ///< Override for the system-wide power base - - std::string disambiguation_string; ///< Disambiguation string for this device - - /// Indices of the variables able to be monitored in the bitset - enum class MonitorableVariables : size_t - { - IR, - II, - P, - Q, - DELTA, - OMEGA, - MAXIMUM, - }; - - /// Set of variables being monitored - std::bitset>(MonitorableVariables::MAXIMUM)> - monitored_variables; - }; + GenrouData() = default; - /// JSON parser function implementation for the `GenrouData` type - /// - /// See the `README.md` in `src/Model/PhasorDynamics` for more information - template - void from_json(const json& j, GenrouData& gd) - { - for (auto& raw_parameter : j.at("params").items()) - { - if (raw_parameter.key() == "p0") - { - raw_parameter.value().get_to(gd.p0); - } - else if (raw_parameter.key() == "q0") - { - raw_parameter.value().get_to(gd.q0); - } - else if (raw_parameter.key() == "H") - { - raw_parameter.value().get_to(gd.H); - } - else if (raw_parameter.key() == "D") - { - raw_parameter.value().get_to(gd.D); - } - else if (raw_parameter.key() == "Ra") - { - raw_parameter.value().get_to(gd.Ra); - } - else if (raw_parameter.key() == "Tdop") - { - raw_parameter.value().get_to(gd.Tdop); - } - else if (raw_parameter.key() == "Tdopp") - { - raw_parameter.value().get_to(gd.Tdopp); - } - else if (raw_parameter.key() == "Tqopp") - { - raw_parameter.value().get_to(gd.Tqopp); - } - else if (raw_parameter.key() == "Tqop") - { - raw_parameter.value().get_to(gd.Tqop); - } - else if (raw_parameter.key() == "Xd") - { - raw_parameter.value().get_to(gd.Xd); - } - else if (raw_parameter.key() == "Xdp") - { - raw_parameter.value().get_to(gd.Xdp); - } - else if (raw_parameter.key() == "Xdpp") - { - raw_parameter.value().get_to(gd.Xdpp); - } - else if (raw_parameter.key() == "Xq") - { - raw_parameter.value().get_to(gd.Xq); - } - else if (raw_parameter.key() == "Xqp") - { - raw_parameter.value().get_to(gd.Xqp); - } - else if (raw_parameter.key() == "Xqpp") - { - raw_parameter.value().get_to(gd.Xqpp); - } - else if (raw_parameter.key() == "Xl") - { - raw_parameter.value().get_to(gd.Xl); - } - else if (raw_parameter.key() == "S10") - { - raw_parameter.value().get_to(gd.S10); - } - else if (raw_parameter.key() == "S12") - { - raw_parameter.value().get_to(gd.S12); - } - else - { - throw "Invalid initial parameter"; - } - } - - for (auto& raw_port : j.at("ports").items()) - { - if (raw_port.key() == "bus") - { - raw_port.value().get_to(gd.bus_id); - } - else if (raw_port.key() == "governor_signal") - { - raw_port.value().get_to(gd.governor_signal); - } - else if (raw_port.key() == "exciter_signal") - { - raw_port.value().get_to(gd.exciter_signal); - } - else - { - throw "Invalid port mapping"; - } - } - - if (j.contains("freq_base")) - { - j.at("freq_base").get_to(gd.freq_base); - } - - if (j.contains("va_base")) - { - j.at("va_base").get_to(gd.va_base); - } - - j.at("id").get_to(gd.disambiguation_string); - - if (j.contains("mon")) - { - for (auto& raw_monitored_variable : j.at("mon")) - { - auto monitored = raw_monitored_variable.get(); - if (monitored == "ir") - { - gd.monitored_variables.set(static_cast( - GenrouData::MonitorableVariables::IR)); - } - else if (monitored == "ii") - { - gd.monitored_variables.set(static_cast( - GenrouData::MonitorableVariables::II)); - } - else if (monitored == "p") - { - gd.monitored_variables.set(static_cast( - GenrouData::MonitorableVariables::P)); - } - else if (monitored == "q") - { - gd.monitored_variables.set(static_cast( - GenrouData::MonitorableVariables::Q)); - } - else if (monitored == "delta") - { - gd.monitored_variables.set(static_cast( - GenrouData::MonitorableVariables::DELTA)); - } - else if (monitored == "omega") - { - gd.monitored_variables.set(static_cast( - GenrouData::MonitorableVariables::OMEGA)); - } - else - { - throw "Invalid monitored variable"; - } - } - } - } + using Parameters = GenrouParameters; + using Ports = GenrouPorts; + using MonitorableVariables = GenrouMonitorableVariables; + }; } // namespace PhasorDynamics } // namespace GridKit From 620837632fddf79cc021ff2cec95c478abd0944e Mon Sep 17 00:00:00 2001 From: superwhiskers Date: Tue, 8 Jul 2025 11:09:18 -0400 Subject: [PATCH 07/16] finish the data structure reworking started in the previous commit --- .../Tiny/ThreeBus/Basic/ThreeBusBasic.cpp | 136 +++---- .../Tiny/TwoBus/Basic/TwoBusBasic.cpp | 63 +-- .../Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp | 63 +-- src/Model/PhasorDynamics/Branch/Branch.cpp | 363 ++++++++++-------- src/Model/PhasorDynamics/Branch/Branch.hpp | 288 +++++++------- src/Model/PhasorDynamics/Load/Load.hpp | 210 +++++----- src/Model/PhasorDynamics/Load/LoadImpl.hpp | 254 ++++++------ .../SynchronousMachine/GENROUwS/Genrou.cpp | 119 ++++-- .../SynchronousMachine/GENROUwS/Genrou.hpp | 40 +- src/Model/PhasorDynamics/SystemModel.hpp | 28 +- .../UnitTests/PhasorDynamics/SystemTests.hpp | 16 +- tests/UnitTests/Utilities/CaseFormatTests.hpp | 86 +++-- 12 files changed, 900 insertions(+), 766 deletions(-) diff --git a/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp b/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp index dea79505a..6ea319f7c 100644 --- a/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp +++ b/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp @@ -8,13 +8,12 @@ * compares results with data generated for the same system by Poweworld. * */ -#include "ThreeBusBasic.hpp" - #include #include #include #include +#include "ThreeBusBasic.hpp" #include #include #include @@ -83,6 +82,7 @@ int main() { using namespace GridKit::PhasorDynamics; using namespace AnalysisManager::Sundials; + using BusType = BusData::BusType; auto error_allowed = static_cast(1e-4); @@ -99,19 +99,19 @@ int main() // Bus 0 data.bus[0].bus_id = 0; - data.bus[0].bus_type = BusData::BusType::SLACK; + data.bus[0].bus_type = BusType::SLACK; data.bus[0].Vr0 = 1.06; data.bus[0].Vi0 = 0.0; // Bus 1 data.bus[1].bus_id = 1; - data.bus[1].bus_type = BusData::BusType::DEFAULT; + data.bus[1].bus_type = BusType::DEFAULT; data.bus[1].Vr0 = 1.0599558398065716; data.bus[1].Vi0 = -0.009675621941024773; // Bus 2 data.bus[2].bus_id = 2; - data.bus[2].bus_type = BusData::BusType::DEFAULT; + data.bus[2].bus_type = BusType::DEFAULT; data.bus[2].Vr0 = 0.9610827543495831; data.bus[2].Vi0 = -0.13122476630506485; @@ -119,89 +119,89 @@ int main() data.branch.resize(3); // Branch 0-1 - data.branch[0].bus1_id = data.bus[0].bus_id; - data.branch[0].bus2_id = data.bus[1].bus_id; - data.branch[0].R = 0.05; - data.branch[0].X = 0.21; - data.branch[0].G = 0; - data.branch[0].B = 0.1; + data.branch[0].ports[BranchPorts::bus1] = data.bus[0].bus_id; + data.branch[0].ports[BranchPorts::bus2] = data.bus[1].bus_id; + data.branch[0].parameters[BranchParameters::R] = 0.05; + data.branch[0].parameters[BranchParameters::X] = 0.21; + data.branch[0].parameters[BranchParameters::G] = 0.; + data.branch[0].parameters[BranchParameters::B] = 0.1; // Branch 0-2 - data.branch[1].bus1_id = data.bus[0].bus_id; - data.branch[1].bus2_id = data.bus[2].bus_id; - data.branch[1].R = 0.06; - data.branch[1].X = 0.15; - data.branch[1].G = 0; - data.branch[1].B = 0.12; + data.branch[1].ports[BranchPorts::bus1] = data.bus[0].bus_id; + data.branch[1].ports[BranchPorts::bus2] = data.bus[2].bus_id; + data.branch[1].parameters[BranchParameters::R] = 0.06; + data.branch[1].parameters[BranchParameters::X] = 0.15; + data.branch[1].parameters[BranchParameters::G] = 0.; + data.branch[1].parameters[BranchParameters::B] = 0.12; // Branch 1-2 - data.branch[2].bus1_id = data.bus[1].bus_id; - data.branch[2].bus2_id = data.bus[2].bus_id; - data.branch[2].R = 0.08; - data.branch[2].X = 0.27; - data.branch[2].G = 0; - data.branch[2].B = 0.45; + data.branch[2].ports[BranchPorts::bus1] = data.bus[1].bus_id; + data.branch[2].ports[BranchPorts::bus2] = data.bus[2].bus_id; + data.branch[2].parameters[BranchParameters::R] = 0.08; + data.branch[2].parameters[BranchParameters::X] = 0.27; + data.branch[2].parameters[BranchParameters::G] = 0.; + data.branch[2].parameters[BranchParameters::B] = 0.45; // Set generator data data.genrou.resize(2); // Generator on bus 1 - data.genrou[0].bus_id = 1; - data.genrou[0].p0 = 0.5; - data.genrou[0].q0 = -0.07588; - data.genrou[0].H = 2.7; - data.genrou[0].D = 0.; - data.genrou[0].Ra = 0.; - data.genrou[0].Tdop = 7.; - data.genrou[0].Tdopp = .04; - data.genrou[0].Tqopp = .05; - data.genrou[0].Tqop = .75; - data.genrou[0].Xd = 1.9; - data.genrou[0].Xdp = 0.17; - data.genrou[0].Xdpp = 0.15; - data.genrou[0].Xq = 0.4; - data.genrou[0].Xqp = 0.35; - data.genrou[0].Xqpp = 0.15; - data.genrou[0].Xl = 0.14999; - data.genrou[0].S10 = 0.; - data.genrou[0].S12 = 0.; + data.genrou[0].ports[GenrouPorts::bus] = 1; + data.genrou[0].parameters[GenrouParameters::p0] = 0.5; + data.genrou[0].parameters[GenrouParameters::q0] = -0.07588; + data.genrou[0].parameters[GenrouParameters::H] = 2.7; + data.genrou[0].parameters[GenrouParameters::D] = 0.; + data.genrou[0].parameters[GenrouParameters::Ra] = 0.; + data.genrou[0].parameters[GenrouParameters::Tdop] = 7.; + data.genrou[0].parameters[GenrouParameters::Tdopp] = .04; + data.genrou[0].parameters[GenrouParameters::Tqopp] = .05; + data.genrou[0].parameters[GenrouParameters::Tqop] = .75; + data.genrou[0].parameters[GenrouParameters::Xd] = 1.9; + data.genrou[0].parameters[GenrouParameters::Xdp] = 0.17; + data.genrou[0].parameters[GenrouParameters::Xdpp] = 0.15; + data.genrou[0].parameters[GenrouParameters::Xq] = 0.4; + data.genrou[0].parameters[GenrouParameters::Xqp] = 0.35; + data.genrou[0].parameters[GenrouParameters::Xqpp] = 0.15; + data.genrou[0].parameters[GenrouParameters::Xl] = 0.14999; + data.genrou[0].parameters[GenrouParameters::S10] = 0.; + data.genrou[0].parameters[GenrouParameters::S12] = 0.; // Generator on bus 2 - data.genrou[1].bus_id = 2; - data.genrou[1].p0 = 0.25; - data.genrou[1].q0 = 0.26587; - data.genrou[1].H = 1.6; - data.genrou[1].D = 0.; - data.genrou[1].Ra = 0.; - data.genrou[1].Tdop = 7.5; - data.genrou[1].Tdopp = .04; - data.genrou[1].Tqopp = .05; - data.genrou[1].Tqop = .75; - data.genrou[1].Xd = 2.3; - data.genrou[1].Xdp = 0.2; - data.genrou[1].Xdpp = 0.18; - data.genrou[1].Xq = 0.5; - data.genrou[1].Xqp = 0.5; - data.genrou[1].Xqpp = 0.18; - data.genrou[1].Xl = 0.15; - data.genrou[1].S10 = 0.; - data.genrou[1].S12 = 0.; + data.genrou[1].ports[GenrouPorts::bus] = 2; + data.genrou[1].parameters[GenrouParameters::p0] = 0.25; + data.genrou[1].parameters[GenrouParameters::q0] = 0.26587; + data.genrou[1].parameters[GenrouParameters::H] = 1.6; + data.genrou[1].parameters[GenrouParameters::D] = 0.; + data.genrou[1].parameters[GenrouParameters::Ra] = 0.; + data.genrou[1].parameters[GenrouParameters::Tdop] = 7.5; + data.genrou[1].parameters[GenrouParameters::Tdopp] = .04; + data.genrou[1].parameters[GenrouParameters::Tqopp] = .05; + data.genrou[1].parameters[GenrouParameters::Tqop] = .75; + data.genrou[1].parameters[GenrouParameters::Xd] = 2.3; + data.genrou[1].parameters[GenrouParameters::Xdp] = 0.2; + data.genrou[1].parameters[GenrouParameters::Xdpp] = 0.18; + data.genrou[1].parameters[GenrouParameters::Xq] = 0.5; + data.genrou[1].parameters[GenrouParameters::Xqp] = 0.5; + data.genrou[1].parameters[GenrouParameters::Xqpp] = 0.18; + data.genrou[1].parameters[GenrouParameters::Xl] = 0.15; + data.genrou[1].parameters[GenrouParameters::S10] = 0.; + data.genrou[1].parameters[GenrouParameters::S12] = 0.; // Set load data data.load.resize(1); // Load on bus 2 - data.load[0].bus_id = 2; - data.load[0].R = 0.4447197839297772; - data.load[0].X = 0.20330047265361242; + data.load[0].ports[LoadPorts::bus] = 2; + data.load[0].parameters[LoadParameters::R] = 0.4447197839297772; + data.load[0].parameters[LoadParameters::X] = 0.20330047265361242; // Set fault data data.bus_fault.resize(1); - data.bus_fault[0].ports[BusFaultData::Ports::bus] = 2; - data.bus_fault[0].parameters[BusFaultData::Parameters::R] = 0.0; - data.bus_fault[0].parameters[BusFaultData::Parameters::X] = 1e-5; - data.bus_fault[0].parameters[BusFaultData::Parameters::state0] = false; + data.bus_fault[0].ports[BusFaultPorts::bus] = 2; + data.bus_fault[0].parameters[BusFaultParameters::R] = 0.0; + data.bus_fault[0].parameters[BusFaultParameters::X] = 1e-5; + data.bus_fault[0].parameters[BusFaultParameters::state0] = false; // // Instantiate system diff --git a/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp b/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp index b3cb7467d..96f9468dd 100644 --- a/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp +++ b/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp @@ -8,11 +8,10 @@ * compares results with data generated for the same system by Poweworld. * */ -#include "TwoBusBasic.hpp" - #include #include +#include "TwoBusBasic.hpp" #include #include #include @@ -36,6 +35,8 @@ int main() using real_type = double; using index_type = size_t; + using BusType = BusData::BusType; + std::cout << "Example: TwoBusBasic\n"; // @@ -48,53 +49,53 @@ int main() data.bus.resize(2); data.bus[0].bus_id = 0; - data.bus[0].bus_type = BusData::BusType::DEFAULT; + data.bus[0].bus_type = BusType::DEFAULT; data.bus[0].Vr0 = 0.9949877346411762; data.bus[0].Vi0 = 0.09999703952427966; data.bus[1].bus_id = 1; - data.bus[1].bus_type = BusData::BusType::SLACK; + data.bus[1].bus_type = BusType::SLACK; data.bus[1].Vr0 = 1.0; data.bus[1].Vi0 = 0.0; // Set branch data data.branch.resize(1); - data.branch[0].bus1_id = data.bus[0].bus_id; - data.branch[0].bus2_id = data.bus[1].bus_id; - data.branch[0].R = 0.0; - data.branch[0].X = 0.1; - data.branch[0].G = 0.0; - data.branch[0].B = 0.0; + data.branch[0].ports[BranchPorts::bus1] = data.bus[0].bus_id; + data.branch[0].ports[BranchPorts::bus2] = data.bus[1].bus_id; + data.branch[0].parameters[BranchParameters::R] = 0.0; + data.branch[0].parameters[BranchParameters::X] = 0.1; + data.branch[0].parameters[BranchParameters::G] = 0.0; + data.branch[0].parameters[BranchParameters::B] = 0.0; // Set generator data data.genrou.resize(1); - data.genrou[0].p0 = 1.; - data.genrou[0].q0 = 0.05013; - data.genrou[0].H = 3.; - data.genrou[0].D = 0.; - data.genrou[0].Ra = 0.; - data.genrou[0].Tdop = 7.; - data.genrou[0].Tdopp = .04; - data.genrou[0].Tqopp = .05; - data.genrou[0].Tqop = .75; - data.genrou[0].Xd = 2.1; - data.genrou[0].Xdp = 0.2; - data.genrou[0].Xdpp = 0.18; - data.genrou[0].Xq = 0.5; - data.genrou[0].Xqp = 0.5; - data.genrou[0].Xqpp = 0.18; - data.genrou[0].Xl = 0.15; - data.genrou[0].S10 = 0.; - data.genrou[0].S12 = 0.; + data.genrou[0].parameters[GenrouParameters::p0] = 1.; + data.genrou[0].parameters[GenrouParameters::q0] = 0.05013; + data.genrou[0].parameters[GenrouParameters::H] = 3.; + data.genrou[0].parameters[GenrouParameters::D] = 0.; + data.genrou[0].parameters[GenrouParameters::Ra] = 0.; + data.genrou[0].parameters[GenrouParameters::Tdop] = 7.; + data.genrou[0].parameters[GenrouParameters::Tdopp] = .04; + data.genrou[0].parameters[GenrouParameters::Tqopp] = .05; + data.genrou[0].parameters[GenrouParameters::Tqop] = .75; + data.genrou[0].parameters[GenrouParameters::Xd] = 2.1; + data.genrou[0].parameters[GenrouParameters::Xdp] = 0.2; + data.genrou[0].parameters[GenrouParameters::Xdpp] = 0.18; + data.genrou[0].parameters[GenrouParameters::Xq] = 0.5; + data.genrou[0].parameters[GenrouParameters::Xqp] = 0.5; + data.genrou[0].parameters[GenrouParameters::Xqpp] = 0.18; + data.genrou[0].parameters[GenrouParameters::Xl] = 0.15; + data.genrou[0].parameters[GenrouParameters::S10] = 0.; + data.genrou[0].parameters[GenrouParameters::S12] = 0.; // Add faults data.bus_fault.resize(1); - data.bus_fault[0].parameters[BusFaultData::Parameters::R] = 0.0; - data.bus_fault[0].parameters[BusFaultData::Parameters::X] = 1e-3; - data.bus_fault[0].parameters[BusFaultData::Parameters::state0] = false; + data.bus_fault[0].parameters[BusFaultParameters::R] = 0.0; + data.bus_fault[0].parameters[BusFaultParameters::X] = 1e-3; + data.bus_fault[0].parameters[BusFaultParameters::state0] = false; // // Instantiate system model diff --git a/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp b/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp index c42b7b6c1..279b6d79d 100644 --- a/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp +++ b/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp @@ -8,11 +8,10 @@ * compares results with data generated for the same system by Poweworld. * */ -#include "TwoBusTgov1.hpp" - #include #include +#include "TwoBusTgov1.hpp" #include #include #include @@ -38,6 +37,8 @@ int main() using real_type = double; using index_type = size_t; + using BusType = BusData::BusType; + std::cout << "Example: TwoBusTgov1 \n"; // @@ -50,31 +51,31 @@ int main() data.bus.resize(2); data.bus[0].bus_id = 0; - data.bus[0].bus_type = BusData::BusType::DEFAULT; + data.bus[0].bus_type = BusType::DEFAULT; data.bus[0].Vr0 = 0.9949877346411762; data.bus[0].Vi0 = 0.09999703952427966; data.bus[1].bus_id = 1; - data.bus[1].bus_type = BusData::BusType::SLACK; + data.bus[1].bus_type = BusType::SLACK; data.bus[1].Vr0 = 1.0; data.bus[1].Vi0 = 0.0; // Set branch data data.branch.resize(1); - data.branch[0].bus1_id = data.bus[0].bus_id; - data.branch[0].bus2_id = data.bus[1].bus_id; - data.branch[0].R = 0.0; - data.branch[0].X = 0.1; - data.branch[0].G = 0.0; - data.branch[0].B = 0.0; + data.branch[0].ports[BranchPorts::bus1] = data.bus[0].bus_id; + data.branch[0].ports[BranchPorts::bus2] = data.bus[1].bus_id; + data.branch[0].parameters[BranchParameters::R] = 0.0; + data.branch[0].parameters[BranchParameters::X] = 0.1; + data.branch[0].parameters[BranchParameters::G] = 0.0; + data.branch[0].parameters[BranchParameters::B] = 0.0; // Add faults data.bus_fault.resize(1); - data.bus_fault[0].parameters[BusFaultData::Parameters::R] = 0.0; - data.bus_fault[0].parameters[BusFaultData::Parameters::X] = 1e-3; - data.bus_fault[0].parameters[BusFaultData::Parameters::state0] = false; + data.bus_fault[0].parameters[BusFaultParameters::R] = 0.0; + data.bus_fault[0].parameters[BusFaultParameters::X] = 1e-3; + data.bus_fault[0].parameters[BusFaultParameters::state0] = false; // // Instantiate system model @@ -85,24 +86,24 @@ int main() // Set generator data data.genrou.resize(1); - data.genrou[0].p0 = 1.; - data.genrou[0].q0 = 0.05013; - data.genrou[0].H = 3.; - data.genrou[0].D = 0.; - data.genrou[0].Ra = 0.; - data.genrou[0].Tdop = 7.; - data.genrou[0].Tdopp = .04; - data.genrou[0].Tqopp = .05; - data.genrou[0].Tqop = .75; - data.genrou[0].Xd = 2.1; - data.genrou[0].Xdp = 0.2; - data.genrou[0].Xdpp = 0.18; - data.genrou[0].Xq = 0.5; - data.genrou[0].Xqp = 0.5; - data.genrou[0].Xqpp = 0.18; - data.genrou[0].Xl = 0.15; - data.genrou[0].S10 = 0.; - data.genrou[0].S12 = 0.; + data.genrou[0].parameters[GenrouParameters::p0] = 1.; + data.genrou[0].parameters[GenrouParameters::q0] = 0.05013; + data.genrou[0].parameters[GenrouParameters::H] = 3.; + data.genrou[0].parameters[GenrouParameters::D] = 0.; + data.genrou[0].parameters[GenrouParameters::Ra] = 0.; + data.genrou[0].parameters[GenrouParameters::Tdop] = 7.; + data.genrou[0].parameters[GenrouParameters::Tdopp] = .04; + data.genrou[0].parameters[GenrouParameters::Tqopp] = .05; + data.genrou[0].parameters[GenrouParameters::Tqop] = .75; + data.genrou[0].parameters[GenrouParameters::Xd] = 2.1; + data.genrou[0].parameters[GenrouParameters::Xdp] = 0.2; + data.genrou[0].parameters[GenrouParameters::Xdpp] = 0.18; + data.genrou[0].parameters[GenrouParameters::Xq] = 0.5; + data.genrou[0].parameters[GenrouParameters::Xqp] = 0.5; + data.genrou[0].parameters[GenrouParameters::Xqpp] = 0.18; + data.genrou[0].parameters[GenrouParameters::Xl] = 0.15; + data.genrou[0].parameters[GenrouParameters::S10] = 0.; + data.genrou[0].parameters[GenrouParameters::S12] = 0.; data.gov.resize(1); diff --git a/src/Model/PhasorDynamics/Branch/Branch.cpp b/src/Model/PhasorDynamics/Branch/Branch.cpp index d679b76eb..6a6b2359d 100644 --- a/src/Model/PhasorDynamics/Branch/Branch.cpp +++ b/src/Model/PhasorDynamics/Branch/Branch.cpp @@ -1,170 +1,193 @@ -/** - * @file Branch.hpp - * @author Slaven Peles (peless@ornl.gov) - * @brief Definition of a phasor dynamics branch model. - * - * The model uses Cartesian coordinates. - * - */ - -#include "Branch.hpp" - -#include -#include - -#include -#include - -namespace GridKit -{ - namespace PhasorDynamics - { - /*! - * @brief Constructor for a pi-model branch - * - * Model size: - * - Number of equations = 0 - * - Number of internal variables = 0 - */ - template - Branch::Branch(bus_type* bus1, bus_type* bus2) - : bus1_(bus1), - bus2_(bus2), - R_(0.0), - X_(0.01), - G_(0.0), - B_(0.0), - bus1_id_(0), - bus2_id_(0) - { - size_ = 0; - } - - /** - * @brief Construct a new Branch - * - * @tparam ScalarT - scalar type - * @tparam IdxT - matrix/vector index type - * @param bus1 - pointer to bus-1 - * @param bus2 - pointer to bus-2 - * @param R - line series resistance - * @param X - line series reactance - * @param G - line shunt conductance - * @param B - line shunt charging - */ - template - Branch::Branch(bus_type* bus1, - bus_type* bus2, - real_type R, - real_type X, - real_type G, - real_type B) - : bus1_(bus1), - bus2_(bus2), - R_(R), - X_(X), - G_(G), - B_(B), - bus1_id_(0), - bus2_id_(0) - { - } - - template - Branch::Branch(bus_type* bus1, bus_type* bus2, const model_data_type& data) - : bus1_(bus1), - bus2_(bus2), - R_(data.R), - X_(data.X), - G_(data.G), - B_(data.B), - bus1_id_(data.bus1_id), - bus2_id_(data.bus2_id) - { - size_ = 0; - } - - /** - * @brief Destroy the Branch - * - * @tparam ScalarT - * @tparam IdxT - */ - template - Branch::~Branch() - { - // std::cout << "Destroy Branch..." << std::endl; - } - - /*! - * @brief allocate method computes sparsity pattern of the Jacobian. - */ - template - int Branch::allocate() - { - // std::cout << "Allocate Branch..." << std::endl; - return 0; - } - - /** - * Initialization of the branch model - * - */ - template - int Branch::initialize() - { - return 0; - } - - /** - * \brief Identify differential variables. - */ - template - int Branch::tagDifferentiable() - { - return 0; - } - - /** - * \brief Residual contribution of the branch is pushed to the - * two terminal buses. - * - */ - template - int Branch::evaluateResidual() - { - // std::cout << "Evaluating branch residual ...\n"; - real_type b = -X_ / (R_ * R_ + X_ * X_); - real_type g = R_ / (R_ * R_ + X_ * X_); - - Ir1() += -(g + 0.5 * G_) * Vr1() + (b + 0.5 * B_) * Vi1() + g * Vr2() - b * Vi2(); - Ii1() += -(b + 0.5 * B_) * Vr1() - (g + 0.5 * G_) * Vi1() + b * Vr2() + g * Vi2(); - Ir2() += g * Vr1() - b * Vi1() - (g + 0.5 * G_) * Vr2() + (b + 0.5 * B_) * Vi2(); - Ii2() += b * Vr1() + g * Vi1() - (b + 0.5 * B_) * Vr2() - (g + 0.5 * G_) * Vi2(); - - return 0; - } - - /** - * @brief Jacobian evaluation not implemented yet - * - * @tparam ScalarT - scalar data type - * @tparam IdxT - matrix index data type - * @return int - error code, 0 = success - */ - template - int Branch::evaluateJacobian() - { - std::cout << "Evaluate Jacobian for Branch..." << std::endl; - std::cout << "Jacobian evaluation not implemented!" << std::endl; - return 0; - } - - // Available template instantiations - template class Branch; - template class Branch; - template class Branch; - template class Branch; - - } // namespace PhasorDynamics -} // namespace GridKit +/** + * @file Branch.hpp + * @author Slaven Peles (peless@ornl.gov) + * @brief Definition of a phasor dynamics branch model. + * + * The model uses Cartesian coordinates. + * + */ + +#include +#include + +#include "Branch.hpp" +#include +#include + +namespace GridKit +{ + namespace PhasorDynamics + { + /** + * @brief Constructor for a pi-model branch + * + * Model size: + * - Number of equations = 0 + * - Number of internal variables = 0 + */ + template + Branch::Branch(bus_type* bus1, bus_type* bus2) + : bus1_(bus1), + bus2_(bus2), + R_(0.0), + X_(0.01), + G_(0.0), + B_(0.0), + bus1_id_(0), + bus2_id_(0) + { + size_ = 0; + } + + /** + * @brief Construct a new Branch + * + * @tparam ScalarT - scalar type + * @tparam IdxT - matrix/vector index type + * @param bus1 - pointer to bus-1 + * @param bus2 - pointer to bus-2 + * @param R - line series resistance + * @param X - line series reactance + * @param G - line shunt conductance + * @param B - line shunt charging + */ + template + Branch::Branch(bus_type* bus1, + bus_type* bus2, + real_type R, + real_type X, + real_type G, + real_type B) + : bus1_(bus1), + bus2_(bus2), + R_(R), + X_(X), + G_(G), + B_(B), + bus1_id_(0), + bus2_id_(0) + { + } + + template + Branch::Branch(bus_type* bus1, bus_type* bus2, const model_data_type& data) + : bus1_(bus1), + bus2_(bus2) + { + if (data.parameters.contains(model_data_type::Parameters::R)) + { + R_ = std::get(data.parameters.at(model_data_type::Parameters::R)); + } + + if (data.parameters.contains(model_data_type::Parameters::X)) + { + X_ = std::get(data.parameters.at(model_data_type::Parameters::X)); + } + + if (data.parameters.contains(model_data_type::Parameters::G)) + { + G_ = std::get(data.parameters.at(model_data_type::Parameters::G)); + } + + if (data.parameters.contains(model_data_type::Parameters::B)) + { + B_ = std::get(data.parameters.at(model_data_type::Parameters::B)); + } + + if (data.ports.contains(model_data_type::Ports::bus1)) + { + bus1_id_ = data.ports.at(model_data_type::Ports::bus1); + } + + if (data.ports.contains(model_data_type::Ports::bus2)) + { + bus2_id_ = data.ports.at(model_data_type::Ports::bus2); + } + + size_ = 0; + } + + /** + * @brief Destroy the Branch + * + * @tparam ScalarT + * @tparam IdxT + */ + template + Branch::~Branch() + { + // std::cout << "Destroy Branch..." << std::endl; + } + + /*! + * @brief allocate method computes sparsity pattern of the Jacobian. + */ + template + int Branch::allocate() + { + // std::cout << "Allocate Branch..." << std::endl; + return 0; + } + + /** + * Initialization of the branch model + * + */ + template + int Branch::initialize() + { + return 0; + } + + /** + * \brief Identify differential variables. + */ + template + int Branch::tagDifferentiable() + { + return 0; + } + + /** + * \brief Residual contribution of the branch is pushed to the + * two terminal buses. + * + */ + template + int Branch::evaluateResidual() + { + // std::cout << "Evaluating branch residual ...\n"; + real_type b = -X_ / (R_ * R_ + X_ * X_); + real_type g = R_ / (R_ * R_ + X_ * X_); + + Ir1() += -(g + 0.5 * G_) * Vr1() + (b + 0.5 * B_) * Vi1() + g * Vr2() - b * Vi2(); + Ii1() += -(b + 0.5 * B_) * Vr1() - (g + 0.5 * G_) * Vi1() + b * Vr2() + g * Vi2(); + Ir2() += g * Vr1() - b * Vi1() - (g + 0.5 * G_) * Vr2() + (b + 0.5 * B_) * Vi2(); + Ii2() += b * Vr1() + g * Vi1() - (b + 0.5 * B_) * Vr2() - (g + 0.5 * G_) * Vi2(); + + return 0; + } + + /** + * @brief Jacobian evaluation not implemented yet + * + * @tparam ScalarT - scalar data type + * @tparam IdxT - matrix index data type + * @return int - error code, 0 = success + */ + template + int Branch::evaluateJacobian() + { + std::cout << "Evaluate Jacobian for Branch..." << std::endl; + std::cout << "Jacobian evaluation not implemented!" << std::endl; + return 0; + } + + // Available template instantiations + template class Branch; + template class Branch; + template class Branch; + template class Branch; + + } // namespace PhasorDynamics +} // namespace GridKit diff --git a/src/Model/PhasorDynamics/Branch/Branch.hpp b/src/Model/PhasorDynamics/Branch/Branch.hpp index 3cd577f45..4215f62c8 100644 --- a/src/Model/PhasorDynamics/Branch/Branch.hpp +++ b/src/Model/PhasorDynamics/Branch/Branch.hpp @@ -1,144 +1,144 @@ -/** - * @file Branch.hpp - * @author Slaven Peles (peless@ornl.gov) - * @brief Declaration of a phasor dynamics branch model. - * - * The model uses Cartesian coordinates. - * - */ -#pragma once - -#include - -// Forward declarations. -namespace GridKit -{ - namespace PhasorDynamics - { - template - class BusBase; - - template - struct BranchData; - } // namespace PhasorDynamics -} // namespace GridKit - -namespace GridKit -{ - namespace PhasorDynamics - { - /** - * @brief Implementation of a pi-model branch between two buses. - * - * The model is implemented in Cartesian coordinates. Positive current - * direction is into the busses. - * - */ - template - class Branch : public Component - { - using Component::size_; - using Component::nnz_; - using Component::time_; - using Component::alpha_; - using Component::y_; - using Component::yp_; - using Component::tag_; - using Component::f_; - - using real_type = typename Component::real_type; - using bus_type = BusBase; - using model_data_type = BranchData; - - public: - Branch(bus_type* bus1, bus_type* bus2); - Branch(bus_type* bus1, bus_type* bus2, real_type R, real_type X, real_type G, real_type B); - Branch(bus_type* bus1, bus_type* bus2, const model_data_type& data); - virtual ~Branch(); - - virtual int allocate() override; - virtual int initialize() override; - virtual int tagDifferentiable() override; - virtual int evaluateResidual() override; - virtual int evaluateJacobian() override; - - virtual void updateTime(real_type /* t */, real_type /* a */) override - { - } - - public: - void setR(real_type R) - { - R_ = R; - } - - void setX(real_type X) - { - // std::cout << "Setting X ...\n"; - X_ = X; - } - - void setG(real_type G) - { - G_ = G; - } - - void setB(real_type B) - { - B_ = B; - } - - private: - ScalarT& Vr1() - { - return bus1_->Vr(); - } - - ScalarT& Vi1() - { - return bus1_->Vi(); - } - - ScalarT& Ir1() - { - return bus1_->Ir(); - } - - ScalarT& Ii1() - { - return bus1_->Ii(); - } - - ScalarT& Vr2() - { - return bus2_->Vr(); - } - - ScalarT& Vi2() - { - return bus2_->Vi(); - } - - ScalarT& Ir2() - { - return bus2_->Ir(); - } - - ScalarT& Ii2() - { - return bus2_->Ii(); - } - - private: - bus_type* bus1_; - bus_type* bus2_; - real_type R_; - real_type X_; - real_type G_; - real_type B_; - const IdxT bus1_id_; - const IdxT bus2_id_; - }; - - } // namespace PhasorDynamics -} // namespace GridKit +/** + * @file Branch.hpp + * @author Slaven Peles (peless@ornl.gov) + * @brief Declaration of a phasor dynamics branch model. + * + * The model uses Cartesian coordinates. + * + */ +#pragma once + +#include + +// Forward declarations. +namespace GridKit +{ + namespace PhasorDynamics + { + template + class BusBase; + + template + struct BranchData; + } // namespace PhasorDynamics +} // namespace GridKit + +namespace GridKit +{ + namespace PhasorDynamics + { + /** + * @brief Implementation of a pi-model branch between two buses. + * + * The model is implemented in Cartesian coordinates. Positive current + * direction is into the busses. + * + */ + template + class Branch : public Component + { + using Component::size_; + using Component::nnz_; + using Component::time_; + using Component::alpha_; + using Component::y_; + using Component::yp_; + using Component::tag_; + using Component::f_; + + using real_type = typename Component::real_type; + using bus_type = BusBase; + using model_data_type = BranchData; + + public: + Branch(bus_type* bus1, bus_type* bus2); + Branch(bus_type* bus1, bus_type* bus2, real_type R, real_type X, real_type G, real_type B); + Branch(bus_type* bus1, bus_type* bus2, const model_data_type& data); + virtual ~Branch(); + + virtual int allocate() override; + virtual int initialize() override; + virtual int tagDifferentiable() override; + virtual int evaluateResidual() override; + virtual int evaluateJacobian() override; + + virtual void updateTime(real_type /* t */, real_type /* a */) override + { + } + + public: + void setR(real_type R) + { + R_ = R; + } + + void setX(real_type X) + { + // std::cout << "Setting X ...\n"; + X_ = X; + } + + void setG(real_type G) + { + G_ = G; + } + + void setB(real_type B) + { + B_ = B; + } + + private: + ScalarT& Vr1() + { + return bus1_->Vr(); + } + + ScalarT& Vi1() + { + return bus1_->Vi(); + } + + ScalarT& Ir1() + { + return bus1_->Ir(); + } + + ScalarT& Ii1() + { + return bus1_->Ii(); + } + + ScalarT& Vr2() + { + return bus2_->Vr(); + } + + ScalarT& Vi2() + { + return bus2_->Vi(); + } + + ScalarT& Ir2() + { + return bus2_->Ir(); + } + + ScalarT& Ii2() + { + return bus2_->Ii(); + } + + private: + bus_type* bus1_; + bus_type* bus2_; + real_type R_{0.0}; + real_type X_{0.0}; + real_type G_{0.0}; + real_type B_{0.0}; + IdxT bus1_id_{0}; + IdxT bus2_id_{0}; + }; + + } // namespace PhasorDynamics +} // namespace GridKit diff --git a/src/Model/PhasorDynamics/Load/Load.hpp b/src/Model/PhasorDynamics/Load/Load.hpp index 53ae88985..337da51af 100644 --- a/src/Model/PhasorDynamics/Load/Load.hpp +++ b/src/Model/PhasorDynamics/Load/Load.hpp @@ -1,106 +1,104 @@ - - -#pragma once - -#include - -// Forward declarations. -namespace GridKit -{ - namespace PhasorDynamics - { - template - class BusBase; - - template - struct LoadData; - } // namespace PhasorDynamics -} // namespace GridKit - -namespace GridKit -{ - namespace PhasorDynamics - { - /*! - * @brief Implementation of a constant load. - * - */ - template - class Load : public Component - { - using Component::size_; - using Component::nnz_; - using Component::time_; - using Component::alpha_; - using Component::y_; - using Component::yp_; - using Component::tag_; - using Component::f_; - using Component::J_; - using Component::component_id_; - - using real_type = typename Component::real_type; - using bus_type = BusBase; - using model_data_type = LoadData; - - public: - Load(bus_type* bus); - Load(bus_type* bus, real_type R, real_type X); - Load(bus_type* bus, IdxT component_id); - Load(bus_type* bus, const model_data_type& data); - virtual ~Load(); - - virtual int allocate() override; - virtual int initialize() override; - virtual int tagDifferentiable() override; - virtual int evaluateResidual() override; - virtual int evaluateJacobian() override; - - virtual void updateTime(real_type /* t */, real_type /* a */) override - { - } - - public: - void setR(real_type R) - { - R_ = R; - } - - void setX(real_type X) - { - // std::cout << "Setting X ...\n"; - X_ = X; - } - - private: - ScalarT& Vr() - { - return bus_->Vr(); - } - - ScalarT& Vi() - { - return bus_->Vi(); - } - - ScalarT& Ir() - { - return bus_->Ir(); - } - - ScalarT& Ii() - { - return bus_->Ii(); - } - - public: - int evaluateResidualLocally(ScalarT*, ScalarT*); - - private: - bus_type* bus_{nullptr}; - real_type R_{0.1}; - real_type X_{0.01}; - }; - - } // namespace PhasorDynamics -} // namespace GridKit +#pragma once + +#include + +// Forward declarations. +namespace GridKit +{ + namespace PhasorDynamics + { + template + class BusBase; + + template + struct LoadData; + } // namespace PhasorDynamics +} // namespace GridKit + +namespace GridKit +{ + namespace PhasorDynamics + { + /*! + * @brief Implementation of a constant load. + * + */ + template + class Load : public Component + { + using Component::size_; + using Component::nnz_; + using Component::time_; + using Component::alpha_; + using Component::y_; + using Component::yp_; + using Component::tag_; + using Component::f_; + using Component::J_; + using Component::component_id_; + + using real_type = typename Component::real_type; + using bus_type = BusBase; + using model_data_type = LoadData; + + public: + Load(bus_type* bus); + Load(bus_type* bus, real_type R, real_type X); + Load(bus_type* bus, IdxT component_id); + Load(bus_type* bus, const model_data_type& data); + virtual ~Load(); + + virtual int allocate() override; + virtual int initialize() override; + virtual int tagDifferentiable() override; + virtual int evaluateResidual() override; + virtual int evaluateJacobian() override; + + virtual void updateTime(real_type /* t */, real_type /* a */) override + { + } + + public: + void setR(real_type R) + { + R_ = R; + } + + void setX(real_type X) + { + // std::cout << "Setting X ...\n"; + X_ = X; + } + + private: + ScalarT& Vr() + { + return bus_->Vr(); + } + + ScalarT& Vi() + { + return bus_->Vi(); + } + + ScalarT& Ir() + { + return bus_->Ir(); + } + + ScalarT& Ii() + { + return bus_->Ii(); + } + + public: + int evaluateResidualLocally(ScalarT*, ScalarT*); + + private: + bus_type* bus_{nullptr}; + real_type R_{0.1}; + real_type X_{0.01}; + }; + + } // namespace PhasorDynamics +} // namespace GridKit diff --git a/src/Model/PhasorDynamics/Load/LoadImpl.hpp b/src/Model/PhasorDynamics/Load/LoadImpl.hpp index 37958eea6..01d994fdb 100644 --- a/src/Model/PhasorDynamics/Load/LoadImpl.hpp +++ b/src/Model/PhasorDynamics/Load/LoadImpl.hpp @@ -1,125 +1,129 @@ - -#include -#include - -#include "Load.hpp" -#include -#include - -namespace GridKit -{ - namespace PhasorDynamics - { - /*! - * @brief Constructor for a pi-model load - * - * System sizes: - * - Number of equations = 0 - * - Number of independent variables = 0 - */ - - template - Load::Load(bus_type* bus) - : bus_(bus) - { - size_ = 0; - } - - template - Load::Load(bus_type* bus, - real_type R, - real_type X) - : bus_(bus), - R_(R), - X_(X) - { - } - - template - Load::Load(bus_type* bus, - const model_data_type& data) - : bus_(bus), - R_(data.R), - X_(data.X) - { - } - - template - Load::Load(bus_type* bus, IdxT component_id) - : bus_(bus) - { - size_ = 0; - component_id_ = component_id; - } - - template - Load::~Load() - { - // std::cout << "Destroy Load..." << std::endl; - } - - /*! - * @brief allocate method computes sparsity pattern of the Jacobian. - */ - template - int Load::allocate() - { - // std::cout << "Allocate Load..." << std::endl; - return 0; - } - - /** - * Initialization of the load model - * - */ - template - int Load::initialize() - { - return 0; - } - - /** - * \brief Identify differential variables. - */ - template - int Load::tagDifferentiable() - { - return 0; - } - - /** - * @brief Residual contribution computed locally - * - */ - template - int Load::evaluateResidualLocally(ScalarT* y, ScalarT* f) - { - real_type b = -X_ / (R_ * R_ + X_ * X_); - real_type g = R_ / (R_ * R_ + X_ * X_); - - f[0] = -g * y[0] + b * y[1]; - f[1] = -b * y[0] - g * y[1]; - - return 0; - } - - /** - * @brief Residual contribution of the load is pushed to the bus. - * - */ - template - int Load::evaluateResidual() - { - std::vector y(2); - std::vector f(2); - y[0] = Vr(); - y[1] = Vi(); - evaluateResidualLocally(y.data(), f.data()); - Ir() += f[0]; - Ii() += f[1]; - - return 0; - } - - } // namespace PhasorDynamics -} // namespace GridKit +#include +#include + +#include "Load.hpp" +#include +#include + +namespace GridKit +{ + namespace PhasorDynamics + { + /* + * @brief Constructor for a pi-model load + * + * System sizes: + * - Number of equations = 0 + * - Number of independent variables = 0 + */ + template + Load::Load(bus_type* bus) + : bus_(bus) + { + size_ = 0; + } + + template + Load::Load(bus_type* bus, + real_type R, + real_type X) + : bus_(bus), + R_(R), + X_(X) + { + } + + template + Load::Load(bus_type* bus, + const model_data_type& data) + : bus_(bus) + { + if (data.parameters.contains(model_data_type::Parameters::R)) + { + R_ = std::get(data.parameters.at(model_data_type::Parameters::R)); + } + + if (data.parameters.contains(model_data_type::Parameters::X)) + { + X_ = std::get(data.parameters.at(model_data_type::Parameters::X)); + } + } + + template + Load::Load(bus_type* bus, IdxT component_id) + : bus_(bus) + { + size_ = 0; + component_id_ = component_id; + } + + template + Load::~Load() + { + // std::cout << "Destroy Load..." << std::endl; + } + + /*! + * @brief allocate method computes sparsity pattern of the Jacobian. + */ + template + int Load::allocate() + { + // std::cout << "Allocate Load..." << std::endl; + return 0; + } + + /** + * Initialization of the load model + * + */ + template + int Load::initialize() + { + return 0; + } + + /** + * \brief Identify differential variables. + */ + template + int Load::tagDifferentiable() + { + return 0; + } + + /** + * @brief Residual contribution computed locally + * + */ + template + int Load::evaluateResidualLocally(ScalarT* y, ScalarT* f) + { + real_type b = -X_ / (R_ * R_ + X_ * X_); + real_type g = R_ / (R_ * R_ + X_ * X_); + + f[0] = -g * y[0] + b * y[1]; + f[1] = -b * y[0] - g * y[1]; + + return 0; + } + + /** + * @brief Residual contribution of the load is pushed to the bus. + * + */ + template + int Load::evaluateResidual() + { + std::vector y(2); + std::vector f(2); + y[0] = Vr(); + y[1] = Vi(); + evaluateResidualLocally(y.data(), f.data()); + Ir() += f[0]; + Ii() += f[1]; + + return 0; + } + } // namespace PhasorDynamics +} // namespace GridKit diff --git a/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.cpp b/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.cpp index 3bc8891e4..410708ce3 100644 --- a/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.cpp +++ b/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.cpp @@ -8,11 +8,10 @@ */ #define _USE_MATH_DEFINES -#include "Genrou.hpp" - #include #include +#include "Genrou.hpp" #include #include // <- TODO: Temporary, to be removed. #include @@ -124,28 +123,104 @@ namespace GridKit template Genrou::Genrou(bus_type* bus, const model_data_type& data) : bus_(bus), - busID_(0), unit_id_(1), - gov_(nullptr), // <- TODO: Temporary, to be removed. - p0_(data.p0), - q0_(data.q0), - H_(data.H), - D_(data.D), - Ra_(data.Ra), - Tdop_(data.Tdop), - Tdopp_(data.Tdopp), - Tqopp_(data.Tqopp), - Tqop_(data.Tqop), - Xd_(data.Xd), - Xdp_(data.Xdp), - Xdpp_(data.Xdpp), - Xq_(data.Xq), - Xqp_(data.Xqp), - Xqpp_(data.Xqpp), - Xl_(data.Xl), - S10_(data.S10), - S12_(data.S12) + gov_(nullptr) // <- TODO: Temporary, to be removed. { + if (data.parameters.contains(model_data_type::Parameters::p0)) + { + p0_ = std::get(data.parameters.at(model_data_type::Parameters::p0)); + } + + if (data.parameters.contains(model_data_type::Parameters::q0)) + { + q0_ = std::get(data.parameters.at(model_data_type::Parameters::q0)); + } + + if (data.parameters.contains(model_data_type::Parameters::H)) + { + H_ = std::get(data.parameters.at(model_data_type::Parameters::H)); + } + + if (data.parameters.contains(model_data_type::Parameters::D)) + { + D_ = std::get(data.parameters.at(model_data_type::Parameters::D)); + } + + if (data.parameters.contains(model_data_type::Parameters::Ra)) + { + Ra_ = std::get(data.parameters.at(model_data_type::Parameters::Ra)); + } + + if (data.parameters.contains(model_data_type::Parameters::Tdop)) + { + Tdop_ = std::get(data.parameters.at(model_data_type::Parameters::Tdop)); + } + + if (data.parameters.contains(model_data_type::Parameters::Tdopp)) + { + Tdopp_ = std::get(data.parameters.at(model_data_type::Parameters::Tdopp)); + } + + if (data.parameters.contains(model_data_type::Parameters::Tqopp)) + { + Tqopp_ = std::get(data.parameters.at(model_data_type::Parameters::Tqopp)); + } + + if (data.parameters.contains(model_data_type::Parameters::Tqop)) + { + Tqop_ = std::get(data.parameters.at(model_data_type::Parameters::Tqop)); + } + + if (data.parameters.contains(model_data_type::Parameters::Xd)) + { + Xd_ = std::get(data.parameters.at(model_data_type::Parameters::Xd)); + } + + if (data.parameters.contains(model_data_type::Parameters::Xdp)) + { + Xdp_ = std::get(data.parameters.at(model_data_type::Parameters::Xdp)); + } + + if (data.parameters.contains(model_data_type::Parameters::Xdpp)) + { + Xdpp_ = std::get(data.parameters.at(model_data_type::Parameters::Xdpp)); + } + + if (data.parameters.contains(model_data_type::Parameters::Xq)) + { + Xq_ = std::get(data.parameters.at(model_data_type::Parameters::Xq)); + } + + if (data.parameters.contains(model_data_type::Parameters::Xqp)) + { + Xqp_ = std::get(data.parameters.at(model_data_type::Parameters::Xqp)); + } + + if (data.parameters.contains(model_data_type::Parameters::Xqpp)) + { + Xqpp_ = std::get(data.parameters.at(model_data_type::Parameters::Xqpp)); + } + + if (data.parameters.contains(model_data_type::Parameters::Xl)) + { + Xl_ = std::get(data.parameters.at(model_data_type::Parameters::Xl)); + } + + if (data.parameters.contains(model_data_type::Parameters::S10)) + { + S10_ = std::get(data.parameters.at(model_data_type::Parameters::S10)); + } + + if (data.parameters.contains(model_data_type::Parameters::S12)) + { + S12_ = std::get(data.parameters.at(model_data_type::Parameters::S12)); + } + + if (data.ports.contains(model_data_type::Ports::bus)) + { + busID_ = data.ports.at(model_data_type::Ports::bus); + } + size_ = 20; setDerivedParams(); } diff --git a/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.hpp b/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.hpp index ffeed60af..7b8675550 100644 --- a/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.hpp +++ b/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.hpp @@ -119,33 +119,33 @@ namespace GridKit private: /* Identification */ bus_type* bus_; - const int busID_; - IdxT unit_id_; + IdxT busID_{0}; + IdxT unit_id_; //< @todo this should be removed // Governor Pointer gov_type* gov_; /* Initial terminal conditions */ - ScalarT p0_; - ScalarT q0_; + ScalarT p0_{0.0}; + ScalarT q0_{0.0}; /* Input parameters */ - real_type H_; - real_type D_; - real_type Ra_; - real_type Tdop_; - real_type Tdopp_; - real_type Tqopp_; - real_type Tqop_; - real_type Xd_; - real_type Xdp_; - real_type Xdpp_; - real_type Xq_; - real_type Xqp_; - real_type Xqpp_; - real_type Xl_; - real_type S10_; - real_type S12_; + real_type H_{0.0}; + real_type D_{0.0}; + real_type Ra_{0.0}; + real_type Tdop_{0.0}; + real_type Tdopp_{0.0}; + real_type Tqopp_{0.0}; + real_type Tqop_{0.0}; + real_type Xd_{0.0}; + real_type Xdp_{0.0}; + real_type Xdpp_{0.0}; + real_type Xq_{0.0}; + real_type Xqp_{0.0}; + real_type Xqpp_{0.0}; + real_type Xl_{0.0}; + real_type S10_{0.0}; + real_type S12_{0.0}; /* Derivied parameters */ real_type SA_; diff --git a/src/Model/PhasorDynamics/SystemModel.hpp b/src/Model/PhasorDynamics/SystemModel.hpp index b8f80efb4..7fb9432c6 100644 --- a/src/Model/PhasorDynamics/SystemModel.hpp +++ b/src/Model/PhasorDynamics/SystemModel.hpp @@ -92,21 +92,43 @@ namespace GridKit // Add branches for (const auto& branchdata : data.branch) { - auto* branch = new Branch(getBus(branchdata.bus1_id), getBus(branchdata.bus2_id), branchdata); + IdxT bus1_index = 0; + if (branchdata.ports.contains(BranchData::Ports::bus1)) + { + bus1_index = branchdata.ports.at(BranchData::Ports::bus1); + } + + IdxT bus2_index = 0; + if (branchdata.ports.contains(BranchData::Ports::bus2)) + { + bus2_index = branchdata.ports.at(BranchData::Ports::bus2); + } + + auto* branch = new Branch(getBus(bus1_index), getBus(bus2_index), branchdata); addComponent(branch); } // Add loads for (const auto& loaddata : data.load) { - auto* load = new Load(getBus(loaddata.bus_id), loaddata); + IdxT bus_index = 0; + if (loaddata.ports.contains(LoadData::Ports::bus)) + { + bus_index = loaddata.ports.at(LoadData::Ports::bus); + } + auto* load = new Load(getBus(bus_index), loaddata); addComponent(load); } // Add GENROU generators for (const auto& gendata : data.genrou) { - auto* gen = new Genrou(getBus(gendata.bus_id), gendata); + IdxT bus_index = 0; + if (gendata.ports.contains(GenrouData::Ports::bus)) + { + bus_index = gendata.ports.at(GenrouData::Ports::bus); + } + auto* gen = new Genrou(getBus(bus_index), gendata); addComponent(gen); } diff --git a/tests/UnitTests/PhasorDynamics/SystemTests.hpp b/tests/UnitTests/PhasorDynamics/SystemTests.hpp index e6adb1bc4..39b5e0e81 100644 --- a/tests/UnitTests/PhasorDynamics/SystemTests.hpp +++ b/tests/UnitTests/PhasorDynamics/SystemTests.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -15,6 +16,9 @@ namespace GridKit { namespace Testing { + using GridKit::PhasorDynamics::BranchParameters; + using GridKit::PhasorDynamics::BranchPorts; + template class SystemTests { @@ -66,12 +70,12 @@ namespace GridKit data.branch.resize(1); // Branch 0-1 - data.branch[0].bus1_id = data.bus[0].bus_id; - data.branch[0].bus2_id = data.bus[1].bus_id; - data.branch[0].R = 2.0; - data.branch[0].X = 4.0; - data.branch[0].G = 0.2; - data.branch[0].B = 1.2; + data.branch[0].ports[BranchPorts::bus1] = data.bus[0].bus_id; + data.branch[0].ports[BranchPorts::bus2] = data.bus[1].bus_id; + data.branch[0].parameters[BranchParameters::R] = 2.0; + data.branch[0].parameters[BranchParameters::X] = 4.0; + data.branch[0].parameters[BranchParameters::G] = 0.2; + data.branch[0].parameters[BranchParameters::B] = 1.2; // Create an empty system model system = new PhasorDynamics::SystemModel(data); diff --git a/tests/UnitTests/Utilities/CaseFormatTests.hpp b/tests/UnitTests/Utilities/CaseFormatTests.hpp index 4660d4634..de32b4e73 100644 --- a/tests/UnitTests/Utilities/CaseFormatTests.hpp +++ b/tests/UnitTests/Utilities/CaseFormatTests.hpp @@ -1,6 +1,10 @@ #include +#include +#include +#include #include +#include #include #include #include @@ -15,14 +19,16 @@ namespace GridKit template class CaseFormatTests { - using SystemModelDataT = PhasorDynamics::SystemModelData; - public: CaseFormatTests() = default; ~CaseFormatTests() = default; TestOutcome simpleParse() { + using namespace GridKit::PhasorDynamics; + using BusData = BusData; + using BusType = BusData::BusType; + const char data[] = R"({ "header": { @@ -46,8 +52,8 @@ namespace GridKit ] })"; - TestStatus success = true; - SystemModelDataT result = json::parse(data); + TestStatus success = true; + SystemModelData result = json::parse(data); success *= result.format_version == 0; success *= result.format_revision == 1; @@ -65,57 +71,57 @@ namespace GridKit success *= result.load.size() == 0; success *= result.bus[0].bus_id == 1; - success *= result.bus[0].bus_type == SystemModelDataT::BusDataT::BusType::DEFAULT; + success *= result.bus[0].bus_type == BusType::DEFAULT; success *= result.bus[0].name == "Bus 1"; success *= result.bus[0].Vr0 == 0.994988; success *= result.bus[0].Vi0 == 0.099997; success *= result.bus[0].v_base == 115e3; - success *= result.bus[0].monitored_variables[static_cast(SystemModelDataT::BusDataT::MonitorableVariables::VR)]; - success *= result.bus[0].monitored_variables[static_cast(SystemModelDataT::BusDataT::MonitorableVariables::VI)]; + success *= result.bus[0].monitored_variables[static_cast(BusData::MonitorableVariables::VR)]; + success *= result.bus[0].monitored_variables[static_cast(BusData::MonitorableVariables::VI)]; success *= result.bus[1].bus_id == 2; - success *= result.bus[1].bus_type == SystemModelDataT::BusDataT::BusType::SLACK; + success *= result.bus[1].bus_type == BusType::SLACK; success *= result.bus[1].name == "Bus 2"; success *= result.bus[1].Vr0 == 1.0; success *= result.bus[1].Vi0 == 0.0; success *= result.bus[1].v_base == 115e3; success *= result.bus[1].monitored_variables.none(); - success *= result.branch[0].R == 0.0; - success *= result.branch[0].X == 0.1; - success *= result.branch[0].G == 0.0; - success *= result.branch[0].B == 0.0; - success *= result.branch[0].bus1_id == 1; - success *= result.branch[0].bus2_id == 2; + success *= std::get(result.branch[0].parameters[BranchParameters::R]) == 0.0; + success *= std::get(result.branch[0].parameters[BranchParameters::X]) == 0.1; + success *= std::get(result.branch[0].parameters[BranchParameters::G]) == 0.0; + success *= std::get(result.branch[0].parameters[BranchParameters::B]) == 0.0; + success *= result.branch[0].ports[BranchPorts::bus1] == 1; + success *= result.branch[0].ports[BranchPorts::bus2] == 2; success *= result.branch[0].disambiguation_string == "1"; - success *= result.branch[0].monitored_variables.none(); + success *= result.branch[0].monitored_variables.empty(); - success *= result.genrou[0].p0 == 1.0; - success *= result.genrou[0].q0 == 0.05013; - success *= result.genrou[0].H == 3.0; - success *= result.genrou[0].D == 0.0; - success *= result.genrou[0].Ra == 0.0; - success *= result.genrou[0].Tdop == 7.0; - success *= result.genrou[0].Tdopp == 0.04; - success *= result.genrou[0].Tqop == 0.75; - success *= result.genrou[0].Tqopp == 0.05; - success *= result.genrou[0].Xd == 2.1; - success *= result.genrou[0].Xdp == 0.2; - success *= result.genrou[0].Xdpp == 0.18; - success *= result.genrou[0].Xq == 0.5; - success *= result.genrou[0].Xqp == 0.0; - success *= result.genrou[0].Xqpp == 0.18; - success *= result.genrou[0].Xl == 0.15; - success *= result.genrou[0].S10 == 0.0; - success *= result.genrou[0].S12 == 0.0; - success *= result.genrou[0].bus_id == 1; + success *= std::get(result.genrou[0].parameters[GenrouParameters::p0]) == 1.0; + success *= std::get(result.genrou[0].parameters[GenrouParameters::q0]) == 0.05013; + success *= std::get(result.genrou[0].parameters[GenrouParameters::H]) == 3.0; + success *= std::get(result.genrou[0].parameters[GenrouParameters::D]) == 0.0; + success *= std::get(result.genrou[0].parameters[GenrouParameters::Ra]) == 0.0; + success *= std::get(result.genrou[0].parameters[GenrouParameters::Tdop]) == 7.0; + success *= std::get(result.genrou[0].parameters[GenrouParameters::Tdopp]) == 0.04; + success *= std::get(result.genrou[0].parameters[GenrouParameters::Tqop]) == 0.75; + success *= std::get(result.genrou[0].parameters[GenrouParameters::Tqopp]) == 0.05; + success *= std::get(result.genrou[0].parameters[GenrouParameters::Xd]) == 2.1; + success *= std::get(result.genrou[0].parameters[GenrouParameters::Xdp]) == 0.2; + success *= std::get(result.genrou[0].parameters[GenrouParameters::Xdpp]) == 0.18; + success *= std::get(result.genrou[0].parameters[GenrouParameters::Xq]) == 0.5; + success *= std::get(result.genrou[0].parameters[GenrouParameters::Xqp]) == 0.0; + success *= std::get(result.genrou[0].parameters[GenrouParameters::Xqpp]) == 0.18; + success *= std::get(result.genrou[0].parameters[GenrouParameters::Xl]) == 0.15; + success *= std::get(result.genrou[0].parameters[GenrouParameters::S10]) == 0.0; + success *= std::get(result.genrou[0].parameters[GenrouParameters::S12]) == 0.0; + success *= result.genrou[0].ports[GenrouPorts::bus] == 1; success *= result.genrou[0].disambiguation_string == "1"; - success *= result.genrou[0].monitored_variables[static_cast(SystemModelDataT::GenrouDataT::MonitorableVariables::DELTA)]; - success *= result.genrou[0].monitored_variables[static_cast(SystemModelDataT::GenrouDataT::MonitorableVariables::OMEGA)]; + success *= result.genrou[0].monitored_variables.contains(GenrouMonitorableVariables::delta); + success *= result.genrou[0].monitored_variables.contains(GenrouMonitorableVariables::omega); - success *= std::get(result.bus_fault[0].parameters[SystemModelDataT::BusFaultDataT::Parameters::R]) == 0.0; - success *= std::get(result.bus_fault[0].parameters[SystemModelDataT::BusFaultDataT::Parameters::X]) == 1e-3; - success *= std::get(result.bus_fault[0].parameters[SystemModelDataT::BusFaultDataT::Parameters::state0]) == false; - success *= result.bus_fault[0].ports[SystemModelDataT::BusFaultDataT::Ports::bus] == 1; + success *= std::get(result.bus_fault[0].parameters[BusFaultParameters::R]) == 0.0; + success *= std::get(result.bus_fault[0].parameters[BusFaultParameters::X]) == 1e-3; + success *= !std::get(result.bus_fault[0].parameters[BusFaultParameters::state0]); + success *= result.bus_fault[0].ports[BusFaultPorts::bus] == 1; success *= result.bus_fault[0].disambiguation_string == "1"; success *= result.bus_fault[0].monitored_variables.empty(); From 7f2f902fceeffc2cb9d144cc33b166dc642b3ec9 Mon Sep 17 00:00:00 2001 From: superwhiskers Date: Tue, 8 Jul 2025 15:19:56 +0000 Subject: [PATCH 08/16] Apply pre-commmit fixes --- .../Tiny/ThreeBus/Basic/ThreeBusBasic.cpp | 3 ++- .../Tiny/TwoBus/Basic/TwoBusBasic.cpp | 3 ++- .../Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp | 3 ++- src/Model/PhasorDynamics/Branch/Branch.cpp | 3 ++- src/Model/PhasorDynamics/Branch/Branch.hpp | 16 ++++++++-------- .../SynchronousMachine/GENROUwS/Genrou.cpp | 3 ++- 6 files changed, 18 insertions(+), 13 deletions(-) diff --git a/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp b/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp index 6ea319f7c..7725c0cfd 100644 --- a/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp +++ b/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp @@ -8,12 +8,13 @@ * compares results with data generated for the same system by Poweworld. * */ +#include "ThreeBusBasic.hpp" + #include #include #include #include -#include "ThreeBusBasic.hpp" #include #include #include diff --git a/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp b/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp index 96f9468dd..1d614ccfb 100644 --- a/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp +++ b/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp @@ -8,10 +8,11 @@ * compares results with data generated for the same system by Poweworld. * */ +#include "TwoBusBasic.hpp" + #include #include -#include "TwoBusBasic.hpp" #include #include #include diff --git a/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp b/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp index 279b6d79d..eca4f0b86 100644 --- a/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp +++ b/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp @@ -8,10 +8,11 @@ * compares results with data generated for the same system by Poweworld. * */ +#include "TwoBusTgov1.hpp" + #include #include -#include "TwoBusTgov1.hpp" #include #include #include diff --git a/src/Model/PhasorDynamics/Branch/Branch.cpp b/src/Model/PhasorDynamics/Branch/Branch.cpp index 6a6b2359d..e38753a73 100644 --- a/src/Model/PhasorDynamics/Branch/Branch.cpp +++ b/src/Model/PhasorDynamics/Branch/Branch.cpp @@ -7,10 +7,11 @@ * */ +#include "Branch.hpp" + #include #include -#include "Branch.hpp" #include #include diff --git a/src/Model/PhasorDynamics/Branch/Branch.hpp b/src/Model/PhasorDynamics/Branch/Branch.hpp index 4215f62c8..5be4657c6 100644 --- a/src/Model/PhasorDynamics/Branch/Branch.hpp +++ b/src/Model/PhasorDynamics/Branch/Branch.hpp @@ -130,14 +130,14 @@ namespace GridKit } private: - bus_type* bus1_; - bus_type* bus2_; - real_type R_{0.0}; - real_type X_{0.0}; - real_type G_{0.0}; - real_type B_{0.0}; - IdxT bus1_id_{0}; - IdxT bus2_id_{0}; + bus_type* bus1_; + bus_type* bus2_; + real_type R_{0.0}; + real_type X_{0.0}; + real_type G_{0.0}; + real_type B_{0.0}; + IdxT bus1_id_{0}; + IdxT bus2_id_{0}; }; } // namespace PhasorDynamics diff --git a/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.cpp b/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.cpp index 410708ce3..0d4a88746 100644 --- a/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.cpp +++ b/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.cpp @@ -8,10 +8,11 @@ */ #define _USE_MATH_DEFINES +#include "Genrou.hpp" + #include #include -#include "Genrou.hpp" #include #include // <- TODO: Temporary, to be removed. #include From 26a6df452262fe7d0b006fe98493bf099992de38 Mon Sep 17 00:00:00 2001 From: superwhiskers Date: Tue, 8 Jul 2025 14:51:36 -0400 Subject: [PATCH 09/16] fix documentation comment in `LoadImpl.hpp` --- src/Model/PhasorDynamics/Load/LoadImpl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Model/PhasorDynamics/Load/LoadImpl.hpp b/src/Model/PhasorDynamics/Load/LoadImpl.hpp index 01d994fdb..6cb57edfb 100644 --- a/src/Model/PhasorDynamics/Load/LoadImpl.hpp +++ b/src/Model/PhasorDynamics/Load/LoadImpl.hpp @@ -9,7 +9,7 @@ namespace GridKit { namespace PhasorDynamics { - /* + /** * @brief Constructor for a pi-model load * * System sizes: From 4a4d72cbf575ae75eaab3759adb604070f34cbb2 Mon Sep 17 00:00:00 2001 From: superwhiskers Date: Tue, 8 Jul 2025 14:54:29 -0400 Subject: [PATCH 10/16] remove extraneous parens in `SystemModelData.hpp` --- src/Model/PhasorDynamics/SystemModelData.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Model/PhasorDynamics/SystemModelData.hpp b/src/Model/PhasorDynamics/SystemModelData.hpp index 3acdf4e4e..b58d99b9d 100644 --- a/src/Model/PhasorDynamics/SystemModelData.hpp +++ b/src/Model/PhasorDynamics/SystemModelData.hpp @@ -123,7 +123,7 @@ namespace GridKit else if (kind == "bus_fault") { typename SystemModelData::BusFaultDataT bus_fault; - raw_component.get_to((bus_fault)); + raw_component.get_to(bus_fault); sm.bus_fault.push_back(bus_fault); } else From 4270567932f4b6d80958e45f72c36fdee9a65837 Mon Sep 17 00:00:00 2001 From: superwhiskers Date: Wed, 9 Jul 2025 08:21:30 -0400 Subject: [PATCH 11/16] fix the `ThreeBusClassical` example --- .../ThreeBus/Classical/ThreeBusClassical.cpp | 59 ++++++++++--------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp b/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp index ffa6a1560..b618880b6 100644 --- a/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp +++ b/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp @@ -8,13 +8,12 @@ * compares results with data generated for the same system by Poweworld. * */ -#include "ThreeBusClassical.hpp" - #include #include #include #include +#include "ThreeBusClassical.hpp" #include #include #include @@ -35,6 +34,8 @@ using scalar_type = double; using real_type = double; using index_type = size_t; +using BusType = GridKit::PhasorDynamics::BusData::BusType; + struct OutputData { real_type t; @@ -99,13 +100,13 @@ int main() // Bus 0 data.bus[0].bus_id = 0; - data.bus[0].bus_type = BusData::BusType::SLACK; + data.bus[0].bus_type = BusType::SLACK; data.bus[0].Vr0 = 1.06; data.bus[0].Vi0 = 0.0; // Bus 1 data.bus[1].bus_id = 1; - data.bus[1].bus_type = BusData::BusType::DEFAULT; + data.bus[1].bus_type = BusType::DEFAULT; data.bus[1].Vr0 = 1.0599558398065716; data.bus[1].Vi0 = -0.009675621941024773; @@ -119,28 +120,28 @@ int main() data.branch.resize(3); // Branch 0-1 - data.branch[0].bus1_id = data.bus[0].bus_id; - data.branch[0].bus2_id = data.bus[1].bus_id; - data.branch[0].R = 0.05; - data.branch[0].X = 0.21; - data.branch[0].G = 0; - data.branch[0].B = 0.1; + data.branch[0].ports[BranchPorts::bus1] = data.bus[0].bus_id; + data.branch[0].ports[BranchPorts::bus2] = data.bus[1].bus_id; + data.branch[0].parameters[BranchParameters::R] = 0.05; + data.branch[0].parameters[BranchParameters::X] = 0.21; + data.branch[0].parameters[BranchParameters::G] = 0.0; + data.branch[0].parameters[BranchParameters::B] = 0.1; // Branch 0-2 - data.branch[1].bus1_id = data.bus[0].bus_id; - data.branch[1].bus2_id = data.bus[2].bus_id; - data.branch[1].R = 0.06; - data.branch[1].X = 0.15; - data.branch[1].G = 0; - data.branch[1].B = 0.12; + data.branch[1].ports[BranchPorts::bus1] = data.bus[0].bus_id; + data.branch[1].ports[BranchPorts::bus2] = data.bus[2].bus_id; + data.branch[1].parameters[BranchParameters::R] = 0.06; + data.branch[1].parameters[BranchParameters::X] = 0.15; + data.branch[1].parameters[BranchParameters::G] = 0.0; + data.branch[1].parameters[BranchParameters::B] = 0.12; // Branch 1-2 - data.branch[2].bus1_id = data.bus[1].bus_id; - data.branch[2].bus2_id = data.bus[2].bus_id; - data.branch[2].R = 0.08; - data.branch[2].X = 0.27; - data.branch[2].G = 0; - data.branch[2].B = 0.45; + data.branch[2].ports[BranchPorts::bus1] = data.bus[1].bus_id; + data.branch[2].ports[BranchPorts::bus2] = data.bus[2].bus_id; + data.branch[2].parameters[BranchParameters::R] = 0.08; + data.branch[2].parameters[BranchParameters::X] = 0.27; + data.branch[2].parameters[BranchParameters::G] = 0.0; + data.branch[2].parameters[BranchParameters::B] = 0.45; // Set generator data data.genclassical.resize(2); @@ -167,17 +168,17 @@ int main() data.load.resize(1); // Load on bus 2 - data.load[0].bus_id = 2; - data.load[0].R = 0.4447197839297772; - data.load[0].X = 0.20330047265361242; + data.load[0].ports[LoadPorts::bus] = 2; + data.load[0].parameters[LoadParameters::R] = 0.4447197839297772; + data.load[0].parameters[LoadParameters::X] = 0.20330047265361242; // Set fault data data.bus_fault.resize(1); - data.bus_fault[0].bus_id = 2; - data.bus_fault[0].R = 0.0; - data.bus_fault[0].X = 1e-5; - data.bus_fault[0].status = false; + data.bus_fault[0].ports[BusFaultPorts::bus] = 2; + data.bus_fault[0].parameters[BusFaultParameters::R] = 0.0; + data.bus_fault[0].parameters[BusFaultParameters::X] = 1e-5; + data.bus_fault[0].parameters[BusFaultParameters::state0] = false; // // Instantiate system From 5fea53d58cb390b579547fc17b1611b1ddbfdb25 Mon Sep 17 00:00:00 2001 From: superwhiskers Date: Wed, 9 Jul 2025 12:22:04 +0000 Subject: [PATCH 12/16] Apply pre-commmit fixes --- .../Tiny/ThreeBus/Classical/ThreeBusClassical.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp b/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp index b618880b6..5e670dced 100644 --- a/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp +++ b/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp @@ -8,12 +8,13 @@ * compares results with data generated for the same system by Poweworld. * */ +#include "ThreeBusClassical.hpp" + #include #include #include #include -#include "ThreeBusClassical.hpp" #include #include #include From 4ac3862f38fb37bae4933520f0f8bedca6ae66f0 Mon Sep 17 00:00:00 2001 From: superwhiskers Date: Wed, 9 Jul 2025 08:42:45 -0400 Subject: [PATCH 13/16] minor fixes to the documentation comments, remove unnecessary no-ops --- .../SynchronousMachine/GENROUwS/Genrou.cpp | 18 +++++---------- .../GenClassical/GenClassical.cpp | 23 +++++-------------- 2 files changed, 12 insertions(+), 29 deletions(-) diff --git a/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.cpp b/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.cpp index 0d4a88746..4d7ceb54a 100644 --- a/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.cpp +++ b/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.cpp @@ -23,8 +23,8 @@ namespace GridKit { namespace PhasorDynamics { - /*! - * @brief Constructor for a pi-model branch + /** + * @brief Constructor for a GENROU generator model with saturation * * Arguments passed to ModelEvaluatorImpl: * - Number of equations = 0 @@ -59,15 +59,10 @@ namespace GridKit { size_ = 20; setDerivedParams(); - - // Temporary, to eliminate compiler warnings - (void) busID_; - (void) unit_id_; } - /*! - * @brief Constructor for a pi-model branch - * + /** + * @brief Constructor for a GENROU generator model with saturation */ template Genrou::Genrou(bus_type* bus, @@ -117,9 +112,8 @@ namespace GridKit setDerivedParams(); } - /*! - * @brief Constructor for the GENROU generator with saturation. - * + /** + * @brief Constructor for a GENROU generator model with saturation */ template Genrou::Genrou(bus_type* bus, const model_data_type& data) diff --git a/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.cpp b/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.cpp index 71da44979..acc3e7b6e 100644 --- a/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.cpp +++ b/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.cpp @@ -8,11 +8,10 @@ */ #define _USE_MATH_DEFINES -#include "GenClassical.hpp" - #include #include +#include "GenClassical.hpp" #include #include @@ -21,8 +20,7 @@ namespace GridKit namespace PhasorDynamics { /** - * @brief Constructor for a classical generator model. - * + * @brief Constructor for a classical generator model */ template GenClassical::GenClassical(bus_type* bus, int unit_id) @@ -38,15 +36,10 @@ namespace GridKit { size_ = 5; setDerivedParams(); - - // Temporary, to eliminate compiler warnings - (void) busID_; - (void) unit_id_; } - /*! - * @brief Constructor for a pi-model branch - * + /** + * @brief Constructor for a classical generator model */ template GenClassical::GenClassical(bus_type* bus, @@ -71,9 +64,8 @@ namespace GridKit setDerivedParams(); } - /*! + /** * @brief Constructor for a classical generator model - * */ template GenClassical::GenClassical(bus_type* bus, const DataT& data) @@ -91,7 +83,7 @@ namespace GridKit setDerivedParams(); } - /*! + /** * @brief allocate method computes sparsity pattern of the Jacobian. */ template @@ -107,7 +99,6 @@ namespace GridKit /** * Initialization of the generator model - * */ template int GenClassical::initialize() @@ -155,7 +146,6 @@ namespace GridKit /** * \brief Residual for the generator model. - * */ template int GenClassical::evaluateResidual() @@ -213,6 +203,5 @@ namespace GridKit // Available template instantiations template class GenClassical; template class GenClassical; - } // namespace PhasorDynamics } // namespace GridKit From d86ff3d0d50572f7e965b310cca155bbc842dc93 Mon Sep 17 00:00:00 2001 From: superwhiskers Date: Wed, 9 Jul 2025 12:43:29 +0000 Subject: [PATCH 14/16] Apply pre-commmit fixes --- .../SynchronousMachine/GenClassical/GenClassical.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.cpp b/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.cpp index acc3e7b6e..235d56a23 100644 --- a/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.cpp +++ b/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.cpp @@ -8,10 +8,11 @@ */ #define _USE_MATH_DEFINES +#include "GenClassical.hpp" + #include #include -#include "GenClassical.hpp" #include #include From ee3d37e0d30c520d2083da5246edcca64c767b17 Mon Sep 17 00:00:00 2001 From: superwhiskers Date: Wed, 9 Jul 2025 12:07:16 -0400 Subject: [PATCH 15/16] address all review comments --- CMakeLists.txt | 9 +- .../ThreeBus/Classical/ThreeBusClassical.cpp | 31 ++- .../PhasorDynamics/Branch/BranchData.hpp | 22 +- src/Model/PhasorDynamics/Bus/BusData.hpp | 92 --------- .../PhasorDynamics/Bus/BusDataJSONParser.hpp | 100 +++++++++ .../PhasorDynamics/BusFault/BusFaultData.hpp | 18 +- src/Model/PhasorDynamics/Load/LoadData.hpp | 10 +- .../GENROUwS/GenrouData.hpp | 82 ++------ .../GenClassical/GenClassical.cpp | 47 ++++- .../GenClassical/GenClassical.hpp | 16 +- .../GenClassical/GenClassicalData.hpp | 192 ++++-------------- src/Model/PhasorDynamics/SystemModel.hpp | 7 +- src/Model/PhasorDynamics/SystemModelData.hpp | 64 +----- .../SystemModelDataJSONParser.hpp | 73 +++++++ tests/UnitTests/Utilities/CMakeLists.txt | 1 + tests/UnitTests/Utilities/CaseFormatTests.hpp | 2 +- 16 files changed, 325 insertions(+), 441 deletions(-) create mode 100644 src/Model/PhasorDynamics/Bus/BusDataJSONParser.hpp create mode 100644 src/Model/PhasorDynamics/SystemModelDataJSONParser.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c897c5ae3..dfd0f3f7a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,8 +83,6 @@ endif("${isSystemDir}" STREQUAL "-1") include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/third-party/nlohmann-json/single_include) -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/third-party/magic-enum/include) option(GRIDKIT_BUILD_SHARED "Build shared libraries" ON) option(GRIDKIT_BUILD_STATIC "Build static libraries" OFF) @@ -109,6 +107,13 @@ if(${GRIDKIT_ENABLE_ENZYME}) add_definitions(-DGRIDKIT_ENABLE_ENZYME) endif() +# add third-party libraries + +set(JSON_BuildTests OFF CACHE INTERNAL "") + +add_subdirectory(third-party/nlohmann-json) +add_subdirectory(third-party/magic-enum) + # Macro that adds libraries include(GridkitAddLibrary) diff --git a/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp b/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp index 5e670dced..f2edac200 100644 --- a/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp +++ b/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp @@ -8,13 +8,12 @@ * compares results with data generated for the same system by Poweworld. * */ -#include "ThreeBusClassical.hpp" - #include #include #include #include +#include "ThreeBusClassical.hpp" #include #include #include @@ -148,22 +147,22 @@ int main() data.genclassical.resize(2); // Generator on bus 1 - data.genclassical[0].bus_id = data.bus[1].bus_id; - data.genclassical[0].p0 = 0.5; - data.genclassical[0].q0 = -0.07588; - data.genclassical[0].H = 2.7; - data.genclassical[0].D = 0.; - data.genclassical[0].Ra = 0.; - data.genclassical[0].Xdp = 0.17; + data.genclassical[0].ports[GenClassicalPorts::bus] = data.bus[1].bus_id; + data.genclassical[0].parameters[GenClassicalParameters::p0] = 0.5; + data.genclassical[0].parameters[GenClassicalParameters::q0] = -0.07588; + data.genclassical[0].parameters[GenClassicalParameters::H] = 2.7; + data.genclassical[0].parameters[GenClassicalParameters::D] = 0.; + data.genclassical[0].parameters[GenClassicalParameters::Ra] = 0.; + data.genclassical[0].parameters[GenClassicalParameters::Xdp] = 0.17; // Generator on bus 2 - data.genclassical[1].bus_id = data.bus[2].bus_id; - data.genclassical[1].p0 = 0.25; - data.genclassical[1].q0 = 0.26587; - data.genclassical[1].H = 1.6; - data.genclassical[1].D = 0.; - data.genclassical[1].Ra = 0.; - data.genclassical[1].Xdp = 0.2; + data.genclassical[1].ports[GenClassicalPorts::bus] = data.bus[2].bus_id; + data.genclassical[1].parameters[GenClassicalParameters::p0] = 0.25; + data.genclassical[1].parameters[GenClassicalParameters::q0] = 0.26587; + data.genclassical[1].parameters[GenClassicalParameters::H] = 1.6; + data.genclassical[1].parameters[GenClassicalParameters::D] = 0.; + data.genclassical[1].parameters[GenClassicalParameters::Ra] = 0.; + data.genclassical[1].parameters[GenClassicalParameters::Xdp] = 0.2; // Set load data data.load.resize(1); diff --git a/src/Model/PhasorDynamics/Branch/BranchData.hpp b/src/Model/PhasorDynamics/Branch/BranchData.hpp index 188eff337..c7851e290 100644 --- a/src/Model/PhasorDynamics/Branch/BranchData.hpp +++ b/src/Model/PhasorDynamics/Branch/BranchData.hpp @@ -15,27 +15,17 @@ namespace GridKit /// Initial parameters for a branch enum class BranchParameters { - /// Line series resistance - R, - - /// Line series reactance - X, - - /// Line shunt conductance - G, - - /// Line shunt charging - B, + R, ///< Line series resistance + X, ///< Line series reactance + G, ///< Line shunt conductance + B, ///< Line shunt charging }; /// Ports for a branch enum class BranchPorts { - /// Unique ID of bus 1 - bus1, - - /// Unique ID of bus 2 - bus2, + bus1, ///< Unique ID of bus 1 + bus2, ///< Unique ID of bus 2 }; /// Variables able to be monitored for a branch diff --git a/src/Model/PhasorDynamics/Bus/BusData.hpp b/src/Model/PhasorDynamics/Bus/BusData.hpp index fb06b19d0..3a1ab6f88 100644 --- a/src/Model/PhasorDynamics/Bus/BusData.hpp +++ b/src/Model/PhasorDynamics/Bus/BusData.hpp @@ -11,14 +11,10 @@ #include #include -#include - namespace GridKit { namespace PhasorDynamics { - using json = nlohmann::json; - /** * @brief Contains modeling data for a Bus * @@ -68,93 +64,5 @@ namespace GridKit std::underlying_type_t>(MonitorableVariables::MAXIMUM)> monitored_variables; }; - - /// JSON parser function implementation for the `BusData` type - /// - /// See the `README.md` in `src/Model/PhasorDynamics` for more information - template - void from_json(const json& j, BusData& bd) - { - j.at("name").get_to(bd.name); - - if (j.contains("init")) - { - for (auto& raw_parameter : j.at("init").items()) - { - if (raw_parameter.key() == "Vi") - { - raw_parameter.value().get_to(bd.Vi0); - } - else if (raw_parameter.key() == "Vr") - { - raw_parameter.value().get_to(bd.Vr0); - } - else - { - throw "Invalid initial parameter"; - } - } - } - - j.at("number").get_to(bd.bus_id); - - auto string_class = j.at("class").get(); - if (string_class == "bus") - { - bd.bus_type = BusData::BusType::DEFAULT; - } - else if (string_class == "infinite_bus") - { - bd.bus_type = BusData::BusType::SLACK; - } - else - { - throw "Invalid bus class"; - } - - j.at("v_base").get_to(bd.v_base); - - if (j.contains("freq_base")) - { - j.at("freq_base").get_to(bd.freq_base); - } - - if (j.contains("va_base")) - { - j.at("va_base").get_to(bd.va_base); - } - - if (j.contains("mon")) - { - for (auto& raw_monitored_variable : j.at("mon")) - { - auto monitored = raw_monitored_variable.get(); - if (monitored == "Vr") - { - bd.monitored_variables.set(static_cast( - BusData::MonitorableVariables::VR)); - } - else if (monitored == "Vi") - { - bd.monitored_variables.set(static_cast( - BusData::MonitorableVariables::VI)); - } - else if (monitored == "Vm") - { - bd.monitored_variables.set(static_cast( - BusData::MonitorableVariables::VM)); - } - else if (monitored == "Va") - { - bd.monitored_variables.set(static_cast( - BusData::MonitorableVariables::VA)); - } - else - { - throw "Invalid monitored variable"; - } - } - } - } } // namespace PhasorDynamics } // namespace GridKit diff --git a/src/Model/PhasorDynamics/Bus/BusDataJSONParser.hpp b/src/Model/PhasorDynamics/Bus/BusDataJSONParser.hpp new file mode 100644 index 000000000..a8b66e44b --- /dev/null +++ b/src/Model/PhasorDynamics/Bus/BusDataJSONParser.hpp @@ -0,0 +1,100 @@ +#pragma once + +#include +#include + +namespace GridKit +{ + namespace PhasorDynamics + { + using json = nlohmann::json; + + /// JSON parser function implementation for the `BusData` type + /// + /// See the `README.md` in `src/Model/PhasorDynamics` for more information + template + void from_json(const json& j, BusData& bd) + { + j.at("name").get_to(bd.name); + + if (j.contains("init")) + { + for (auto& raw_parameter : j.at("init").items()) + { + if (raw_parameter.key() == "Vi") + { + raw_parameter.value().get_to(bd.Vi0); + } + else if (raw_parameter.key() == "Vr") + { + raw_parameter.value().get_to(bd.Vr0); + } + else + { + throw "Invalid initial parameter"; + } + } + } + + j.at("number").get_to(bd.bus_id); + + auto string_class = j.at("class").get(); + if (string_class == "bus") + { + bd.bus_type = BusData::BusType::DEFAULT; + } + else if (string_class == "infinite_bus") + { + bd.bus_type = BusData::BusType::SLACK; + } + else + { + throw "Invalid bus class"; + } + + j.at("v_base").get_to(bd.v_base); + + if (j.contains("freq_base")) + { + j.at("freq_base").get_to(bd.freq_base); + } + + if (j.contains("va_base")) + { + j.at("va_base").get_to(bd.va_base); + } + + if (j.contains("mon")) + { + for (auto& raw_monitored_variable : j.at("mon")) + { + auto monitored = raw_monitored_variable.get(); + if (monitored == "Vr") + { + bd.monitored_variables.set(static_cast( + BusData::MonitorableVariables::VR)); + } + else if (monitored == "Vi") + { + bd.monitored_variables.set(static_cast( + BusData::MonitorableVariables::VI)); + } + else if (monitored == "Vm") + { + bd.monitored_variables.set(static_cast( + BusData::MonitorableVariables::VM)); + } + else if (monitored == "Va") + { + bd.monitored_variables.set(static_cast( + BusData::MonitorableVariables::VA)); + } + else + { + throw "Invalid monitored variable"; + } + } + } + } + } // namespace PhasorDynamics +} // namespace GridKit diff --git a/src/Model/PhasorDynamics/BusFault/BusFaultData.hpp b/src/Model/PhasorDynamics/BusFault/BusFaultData.hpp index 58649d6fc..ed7447ff1 100644 --- a/src/Model/PhasorDynamics/BusFault/BusFaultData.hpp +++ b/src/Model/PhasorDynamics/BusFault/BusFaultData.hpp @@ -15,24 +15,16 @@ namespace GridKit /// Initial parameters for a bus fault enum class BusFaultParameters { - /// Whether or not the fault has happened - state0, - - /// Short to ground resistance - R, - - /// Short to ground reactance - X, + state0, ///< Whether or not the fault has happened + R, ///< Short to ground resistance + X, ///< Short to ground reactance }; /// Ports supported for a bus fault enum class BusFaultPorts { - /// Unique ID of the bus where the fault occurs - bus, - - /// Unique ID of the bus providing a control signal - control_signal, + bus, ///< Unique ID of the bus where the fault occurs + control_signal, ///< Unique ID of the bus providing a control signal }; /// Variables able to be monitored for a bus fault diff --git a/src/Model/PhasorDynamics/Load/LoadData.hpp b/src/Model/PhasorDynamics/Load/LoadData.hpp index e15b6e991..dbd439455 100644 --- a/src/Model/PhasorDynamics/Load/LoadData.hpp +++ b/src/Model/PhasorDynamics/Load/LoadData.hpp @@ -15,18 +15,14 @@ namespace GridKit /// Initial parameters for a load enum class LoadParameters { - /// Load resistance - R, - - /// Load reactance - X, + R, ///< Load resistance + X, ///< Load reactance }; /// Ports for a load enum class LoadPorts { - /// Unique ID of the bus to which the load is connected - bus, + bus, ///< Unique ID of the bus to which the load is connected }; /// Variables able to be monitored for a load diff --git a/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/GenrouData.hpp b/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/GenrouData.hpp index 8300f1049..8e70c77c8 100644 --- a/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/GenrouData.hpp +++ b/src/Model/PhasorDynamics/SynchronousMachine/GENROUwS/GenrouData.hpp @@ -15,72 +15,32 @@ namespace GridKit /// Initial parameters for a Genrou generator model enum class GenrouParameters { - /// Initial active power - p0, - - /// Initial reactive power - q0, - - /// Rotor inertia - H, - - /// Damping coefficient - D, - - /// Winding resistance - Ra, - - /// Open circuit direct axis transient time - Tdop, - - /// Open circuit direct axis sub-transient time - Tdopp, - - /// Open circuit quadrature axis transient - Tqop, - - /// Open circuit quadrature axis sub-transient time - Tqopp, - - /// Direct axis synchronous reactance - Xd, - - /// Direct axis transient reactance - Xdp, - - /// Direct axis sub-transient reactance - Xdpp, - - /// Quadrature axis synchronous reactance - Xq, - - /// Quadrature axis transient reactance - Xqp, - - /// Quadrature axis sub-transient reactance - Xqpp, - - /// Stator leakage reactance - Xl, - - /// Saturation factor at 1.0 pu flux - S10, - - /// Saturation factor at 1.2 pu flux - S12, + p0, ///< Initial active power + q0, ///< Initial reactive power + H, ///< Rotor inertia + D, ///< Damping coefficient + Ra, ///< Winding resistance + Tdop, ///< Open circuit direct axis transient time + Tdopp, ///< Open circuit direct axis sub-transient time + Tqop, ///< Open circuit quadrature axis transient + Tqopp, ///< Open circuit quadrature axis sub-transient time + Xd, ///< Direct axis synchronous reactance + Xdp, ///< Direct axis transient reactance + Xdpp, ///< Direct axis sub-transient reactance + Xq, ///< Quadrature axis synchronous reactance + Xqp, ///< Quadrature axis transient reactance + Xqpp, ///< Quadrature axis sub-transient reactance + Xl, ///< Stator leakage reactance + S10, ///< Saturation factor at 1.0 pu flux + S12, ///< Saturation factor at 1.2 pu flux }; /// Ports for a Genrou generator model enum class GenrouPorts { - /// Unique ID of the connecting bus - bus, - - /// Unique ID of the bus providing the exciter signal - exciter_signal, - - /// Unique ID of the bus providing the governor signal - governor_signal, + bus, ///< Unique ID of the connecting bus + exciter_signal, ///< Unique ID of the bus providing the exciter signal + governor_signal, ///< Unique ID of the bus providing the governor signal }; /// Variables able to be monitored for a Genrou generator model diff --git a/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.cpp b/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.cpp index 235d56a23..5751cbf75 100644 --- a/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.cpp +++ b/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.cpp @@ -8,11 +8,10 @@ */ #define _USE_MATH_DEFINES -#include "GenClassical.hpp" - #include #include +#include "GenClassical.hpp" #include #include @@ -71,15 +70,43 @@ namespace GridKit template GenClassical::GenClassical(bus_type* bus, const DataT& data) : bus_(bus), - busID_(0), - unit_id_(0), - p0_(data.p0), - q0_(data.q0), - H_(data.H), - D_(data.D), - Ra_(data.Ra), - Xdp_(data.Xdp) + unit_id_(1) { + if (data.parameters.contains(DataT::Parameters::p0)) + { + p0_ = std::get(data.parameters.at(DataT::Parameters::p0)); + } + + if (data.parameters.contains(DataT::Parameters::q0)) + { + q0_ = std::get(data.parameters.at(DataT::Parameters::q0)); + } + + if (data.parameters.contains(DataT::Parameters::H)) + { + H_ = std::get(data.parameters.at(DataT::Parameters::H)); + } + + if (data.parameters.contains(DataT::Parameters::D)) + { + D_ = std::get(data.parameters.at(DataT::Parameters::D)); + } + + if (data.parameters.contains(DataT::Parameters::Ra)) + { + Ra_ = std::get(data.parameters.at(DataT::Parameters::Ra)); + } + + if (data.parameters.contains(DataT::Parameters::Xdp)) + { + Xdp_ = std::get(data.parameters.at(DataT::Parameters::Xdp)); + } + + if (data.ports.contains(DataT::Ports::bus)) + { + busID_ = data.ports.at(DataT::Ports::bus); + } + size_ = 5; setDerivedParams(); } diff --git a/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.hpp b/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.hpp index 3c0125ab0..35581ae77 100644 --- a/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.hpp +++ b/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.hpp @@ -104,18 +104,18 @@ namespace GridKit private: /* Identification */ bus_type* bus_; - const int busID_; - int unit_id_; + IdxT busID_{0}; + int unit_id_; //< @todo this should be removed /* Initial terminal conditions */ - ScalarT p0_; - ScalarT q0_; + ScalarT p0_{0.0}; + ScalarT q0_{0.0}; /* Input parameters */ - real_type H_; - real_type D_; - real_type Ra_; - real_type Xdp_; + real_type H_{0.0}; + real_type D_{0.0}; + real_type Ra_{0.0}; + real_type Xdp_{0.0}; /* Derivied parameters */ real_type G_; diff --git a/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassicalData.hpp b/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassicalData.hpp index c29013f32..3ff9cfd75 100644 --- a/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassicalData.hpp +++ b/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassicalData.hpp @@ -6,17 +6,42 @@ */ #pragma once -#include -#include -#include -#include - -#include +#include namespace GridKit { namespace PhasorDynamics { + /// Initial parameters for a classical generator model + enum class GenClassicalParameters + { + p0, ///< Initial active power + q0, ///< Initial reactive power + H, ///< Rotor inertia + D, ///< Damping coefficient + Ra, ///< Winding resistance + Xdp, ///< Direct axis transient reactance + }; + + /// Ports supported for a classical generator model + enum class GenClassicalPorts + { + bus, ///< Unique ID of the connecting bus + exciter_signal, ///< Unique ID of the bus providing the exciter signal + governor_signal, ///< Unique ID of the bus providing the governor signal + }; + + /// Variables able to be monitored for a classical generator model + enum class GenClassicalMonitorableVariables + { + ir, + ii, + p, + q, + delta, + omega, + }; + /** * @brief Contains modeling data for a GenClassical generator model. * @@ -28,154 +53,17 @@ namespace GridKit * @todo Decide on naming scheme for model parameters. */ template - struct GenClassicalData + struct GenClassicalData : public ComponentData { - IdxT unit_id{0}; ///< Unique component ID - RealT p0{0.0}; ///< Initial active power - RealT q0{0.0}; ///< Initial reactive power - RealT H{0.0}; ///< Rotor inertia - RealT D{0.0}; ///< Damping coefficient - RealT Ra{0.0}; ///< Winding resistance - RealT Xdp{0.0}; ///< Direct axis transient reactance - - IdxT bus_id{0}; ///< Unique ID of the connecting bus - std::optional exciter_signal; ///< Unique ID of the bus providing the exciter signal - std::optional governor_signal; ///< Unique ID of the bus providing the governor signal + GenClassicalData() = default; - std::optional freq_base; ///< Override for the system-wide base frequency - std::optional va_base; ///< Override for the system-wide power base - - std::string disambiguation_string; ///< Disambiguation string for this device - - /// Indices of the variables able to be monitored in the bitset - enum class MonitorableVariables : size_t - { - IR, - II, - P, - Q, - DELTA, - OMEGA, - MAXIMUM, - }; - - /// Set of variables being monitored - std::bitset>(MonitorableVariables::MAXIMUM)> - monitored_variables; + using Parameters = GenClassicalParameters; + using Ports = GenClassicalPorts; + using MonitorableVariables = GenClassicalMonitorableVariables; }; - - /// JSON parser function implementation for the `GenClassicalData` type - /// - /// See the `README.md` in `src/Model/PhasorDynamics` for more information - template - void from_json(const json& j, GenClassicalData& gd) - { - for (auto& raw_parameter : j.at("params").items()) - { - if (raw_parameter.key() == "p0") - { - raw_parameter.value().get_to(gd.p0); - } - else if (raw_parameter.key() == "q0") - { - raw_parameter.value().get_to(gd.q0); - } - else if (raw_parameter.key() == "H") - { - raw_parameter.value().get_to(gd.H); - } - else if (raw_parameter.key() == "D") - { - raw_parameter.value().get_to(gd.D); - } - else if (raw_parameter.key() == "Ra") - { - raw_parameter.value().get_to(gd.Ra); - } - else if (raw_parameter.key() == "Xdp") - { - raw_parameter.value().get_to(gd.Xdp); - } - else - { - throw "Invalid initial parameter"; - } - } - - for (auto& raw_port : j.at("ports").items()) - { - if (raw_port.key() == "bus") - { - raw_port.value().get_to(gd.bus_id); - } - else if (raw_port.key() == "governor_signal") - { - raw_port.value().get_to(gd.governor_signal); - } - else if (raw_port.key() == "exciter_signal") - { - raw_port.value().get_to(gd.exciter_signal); - } - else - { - throw "Invalid port mapping"; - } - } - - if (j.contains("freq_base")) - { - j.at("freq_base").get_to(gd.freq_base); - } - - if (j.contains("va_base")) - { - j.at("va_base").get_to(gd.va_base); - } - - j.at("id").get_to(gd.disambiguation_string); - - if (j.contains("mon")) - { - for (auto& raw_monitored_variable : j.at("mon")) - { - auto monitored = raw_monitored_variable.get(); - if (monitored == "ir") - { - gd.monitored_variables.set(static_cast( - GenClassicalData::MonitorableVariables::IR)); - } - else if (monitored == "ii") - { - gd.monitored_variables.set(static_cast( - GenClassicalData::MonitorableVariables::II)); - } - else if (monitored == "p") - { - gd.monitored_variables.set(static_cast( - GenClassicalData::MonitorableVariables::P)); - } - else if (monitored == "q") - { - gd.monitored_variables.set(static_cast( - GenClassicalData::MonitorableVariables::Q)); - } - else if (monitored == "delta") - { - gd.monitored_variables.set(static_cast( - GenClassicalData::MonitorableVariables::DELTA)); - } - else if (monitored == "omega") - { - gd.monitored_variables.set(static_cast( - GenClassicalData::MonitorableVariables::OMEGA)); - } - else - { - throw "Invalid monitored variable"; - } - } - } - } } // namespace PhasorDynamics } // namespace GridKit diff --git a/src/Model/PhasorDynamics/SystemModel.hpp b/src/Model/PhasorDynamics/SystemModel.hpp index 7fb9432c6..dbb256a2c 100644 --- a/src/Model/PhasorDynamics/SystemModel.hpp +++ b/src/Model/PhasorDynamics/SystemModel.hpp @@ -135,7 +135,12 @@ namespace GridKit // Add classical generators for (const auto& gendata : data.genclassical) { - auto* gen = new GenClassical(getBus(gendata.bus_id), gendata); + IdxT bus_index = 0; + if (gendata.ports.contains(GenClassicalData::Ports::bus)) + { + bus_index = gendata.ports.at(GenClassicalData::Ports::bus); + } + auto* gen = new GenClassical(getBus(bus_index), gendata); addComponent(gen); } diff --git a/src/Model/PhasorDynamics/SystemModelData.hpp b/src/Model/PhasorDynamics/SystemModelData.hpp index b58d99b9d..4cddedabb 100644 --- a/src/Model/PhasorDynamics/SystemModelData.hpp +++ b/src/Model/PhasorDynamics/SystemModelData.hpp @@ -1,6 +1,8 @@ #pragma once #include +#include +#include #include #include @@ -9,14 +11,11 @@ #include #include #include -#include namespace GridKit { namespace PhasorDynamics { - using json = nlohmann::json; - /// A structure containing all of the data needed to reproduce a /// system model /// @@ -73,64 +72,5 @@ namespace GridKit std::vector load; ///< Loads within the model std::vector gov; ///< Governors within the model }; - - /// JSON parser function implementation for the `SystemModelData` type - /// - /// See the `README.md` in `src/Model/PhasorDynamics` for more information - template - void from_json(const json& j, SystemModelData& sm) - { - auto header = j.at("header"); - - if (header.contains("format_version")) - { - header.at("format_version").get_to(sm.format_version); - } - - if (header.contains("format_revision")) - { - header.at("format_revision").get_to(sm.format_revision); - } - - header.at("case_name").get_to(sm.case_name); - - if (header.contains("case_date_time")) - { - header.at("case_date_time").get_to(sm.case_date_time); - } - - header.at("case_description").get_to(sm.case_description); - header.at("case_comments").get_to(sm.case_comments); - header.at("freq_base").get_to(sm.freq_base); - header.at("va_base").get_to(sm.va_base); - j.at("buses").get_to(sm.bus); - - for (auto& raw_component : j.at("devices")) - { - auto kind = raw_component.at("class"); - if (kind == "branch") - { - typename SystemModelData::BranchDataT branch; - raw_component.get_to(branch); - sm.branch.push_back(branch); - } - else if (kind == "GENROU") - { - typename SystemModelData::GenrouDataT genrou; - raw_component.get_to(genrou); - sm.genrou.push_back(genrou); - } - else if (kind == "bus_fault") - { - typename SystemModelData::BusFaultDataT bus_fault; - raw_component.get_to(bus_fault); - sm.bus_fault.push_back(bus_fault); - } - else - { - throw "Invalid device class"; - } - } - } } // namespace PhasorDynamics } // namespace GridKit diff --git a/src/Model/PhasorDynamics/SystemModelDataJSONParser.hpp b/src/Model/PhasorDynamics/SystemModelDataJSONParser.hpp new file mode 100644 index 000000000..d9ee36784 --- /dev/null +++ b/src/Model/PhasorDynamics/SystemModelDataJSONParser.hpp @@ -0,0 +1,73 @@ +#pragma once + +#include +#include +#include +#include + +namespace GridKit +{ + namespace PhasorDynamics + { + using json = nlohmann::json; + + /// JSON parser function implementation for the `SystemModelData` type + /// + /// See the `README.md` in `src/Model/PhasorDynamics` for more information + template + void from_json(const json& j, SystemModelData& sm) + { + auto header = j.at("header"); + + if (header.contains("format_version")) + { + header.at("format_version").get_to(sm.format_version); + } + + if (header.contains("format_revision")) + { + header.at("format_revision").get_to(sm.format_revision); + } + + header.at("case_name").get_to(sm.case_name); + + if (header.contains("case_date_time")) + { + header.at("case_date_time").get_to(sm.case_date_time); + } + + header.at("case_description").get_to(sm.case_description); + header.at("case_comments").get_to(sm.case_comments); + header.at("freq_base").get_to(sm.freq_base); + header.at("va_base").get_to(sm.va_base); + j.at("buses").get_to(sm.bus); + + for (auto& raw_component : j.at("devices")) + { + auto kind = raw_component.at("class"); + if (kind == "branch") + { + typename SystemModelData::BranchDataT branch; + raw_component.get_to(branch); + sm.branch.push_back(branch); + } + else if (kind == "GENROU") + { + typename SystemModelData::GenrouDataT genrou; + raw_component.get_to(genrou); + sm.genrou.push_back(genrou); + } + else if (kind == "bus_fault") + { + typename SystemModelData::BusFaultDataT bus_fault; + raw_component.get_to(bus_fault); + sm.bus_fault.push_back(bus_fault); + } + else + { + throw "Invalid device class"; + } + } + } + } // namespace PhasorDynamics +} // namespace GridKit diff --git a/tests/UnitTests/Utilities/CMakeLists.txt b/tests/UnitTests/Utilities/CMakeLists.txt index d1c337fc1..fd9b96b1a 100644 --- a/tests/UnitTests/Utilities/CMakeLists.txt +++ b/tests/UnitTests/Utilities/CMakeLists.txt @@ -1,4 +1,5 @@ add_executable(test_case_format runCaseFormatTests.cpp) +target_link_libraries(test_case_format PRIVATE nlohmann_json::nlohmann_json magic_enum::magic_enum) add_test(NAME UtilitiesCaseFormatTest COMMAND $) diff --git a/tests/UnitTests/Utilities/CaseFormatTests.hpp b/tests/UnitTests/Utilities/CaseFormatTests.hpp index de32b4e73..2a24a4b14 100644 --- a/tests/UnitTests/Utilities/CaseFormatTests.hpp +++ b/tests/UnitTests/Utilities/CaseFormatTests.hpp @@ -3,9 +3,9 @@ #include #include #include -#include #include #include +#include #include #include #include From b7461eb3614caef6300a089886a50522d17d7820 Mon Sep 17 00:00:00 2001 From: superwhiskers Date: Wed, 9 Jul 2025 16:07:48 +0000 Subject: [PATCH 16/16] Apply pre-commmit fixes --- .../Tiny/ThreeBus/Classical/ThreeBusClassical.cpp | 3 ++- .../SynchronousMachine/GenClassical/GenClassical.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp b/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp index f2edac200..78f4dc92f 100644 --- a/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp +++ b/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp @@ -8,12 +8,13 @@ * compares results with data generated for the same system by Poweworld. * */ +#include "ThreeBusClassical.hpp" + #include #include #include #include -#include "ThreeBusClassical.hpp" #include #include #include diff --git a/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.cpp b/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.cpp index 5751cbf75..e9c724477 100644 --- a/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.cpp +++ b/src/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.cpp @@ -8,10 +8,11 @@ */ #define _USE_MATH_DEFINES +#include "GenClassical.hpp" + #include #include -#include "GenClassical.hpp" #include #include