From 3e016462c666d63661d3ba032a89b20d79220d09 Mon Sep 17 00:00:00 2001 From: Alexander Novotny Date: Fri, 28 Aug 2026 15:32:14 -0400 Subject: [PATCH 01/10] Output the correct variable for TenGenGenrou example (#559) * Output the correct variable for TenGenGenrou example * Update CHANGELOG --- CHANGELOG.md | 1 + examples/PhasorDynamics/Small/TenGen/Genrou/TenGenGenrou.cpp | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e3336671..ea51a9bb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -83,6 +83,7 @@ - Added cases and validation for ACTIVSg10k, ACTIVSg200, ACTIVSg500, and WECC240. - Added IDA option to choose the consistent initial condition calculation type. - Implemented `tagDifferentiable()` for `PowerElectronics` models. +- Fixed the `TenGenGenrou` example to output the correct omega values. ## v0.1 diff --git a/examples/PhasorDynamics/Small/TenGen/Genrou/TenGenGenrou.cpp b/examples/PhasorDynamics/Small/TenGen/Genrou/TenGenGenrou.cpp index 402f554be..b140eddc0 100644 --- a/examples/PhasorDynamics/Small/TenGen/Genrou/TenGenGenrou.cpp +++ b/examples/PhasorDynamics/Small/TenGen/Genrou/TenGenGenrou.cpp @@ -135,9 +135,8 @@ int main() for (size_t i = 0; i < 9; ++i) { // 18 is offset for variables of 9 buses. - // Each generator has 21 equations. // We are outputting second equation of each generator. - out << yval[18 + 21 * i + 1] << ","; + out << yval[18 + gen2.size() * i + 1] << ","; } out << "\n"; }; From a8780099a4b7b1950834e4c6f44e43a9f0126b70 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Wed, 26 Aug 2026 06:44:24 +0000 Subject: [PATCH 02/10] Refactor common microgrid code and update examples --- .../PowerElectronics/Microgrid/CMakeLists.txt | 5 + .../PowerElectronics/Microgrid/Microgrid.cpp | 161 +-------- .../MicrogridNetwork.hpp | 309 ++++++++++++++++++ .../ScaleMicrogrid/CMakeLists.txt | 9 + .../ScaleMicrogrid/ScaleMicrogrid.cpp | 166 +--------- .../ScaleMicrogridArbitrary.cpp | 171 +--------- 6 files changed, 368 insertions(+), 453 deletions(-) create mode 100644 examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp diff --git a/examples/PowerElectronics/Microgrid/CMakeLists.txt b/examples/PowerElectronics/Microgrid/CMakeLists.txt index 6eae26be3..86dea6678 100644 --- a/examples/PowerElectronics/Microgrid/CMakeLists.txt +++ b/examples/PowerElectronics/Microgrid/CMakeLists.txt @@ -1,4 +1,9 @@ add_executable(microgrid Microgrid.cpp) + +target_include_directories( + microgrid + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..) + target_link_libraries( microgrid GridKit::power_elec_disgen diff --git a/examples/PowerElectronics/Microgrid/Microgrid.cpp b/examples/PowerElectronics/Microgrid/Microgrid.cpp index dfd71a7e1..e20d9e5ac 100644 --- a/examples/PowerElectronics/Microgrid/Microgrid.cpp +++ b/examples/PowerElectronics/Microgrid/Microgrid.cpp @@ -1,21 +1,13 @@ #include -#include -#include -#include +#include #include -#include -#include - -#include -#include -#include -#include -#include -#include + #include #include #include +#include "Common/MicrogridNetwork.hpp" + int main(int /* argc */, char const** /* argv */) { /// @todo Needs to be modified. Some components are small relative to others thus @@ -28,139 +20,16 @@ int main(int /* argc */, char const** /* argv */) // Create model auto* sysmodel = new GridKit::PowerElectronicsModel(use_jac); - // Modeled after the problem in the paper - double RN = 1.0e4; - - // DG Params - static constexpr auto pi = std::numbers::pi_v; - - GridKit::DistributedGeneratorParameters parms1; - parms1.wb_ = 2.0 * pi * 50.0; - parms1.wc_ = 31.41; - parms1.mp_ = 9.4e-5; - parms1.Vn_ = 380.0; - parms1.nq_ = 1.3e-3; - parms1.F_ = 0.75; - parms1.Kiv_ = 420.0; - parms1.Kpv_ = 0.1; - parms1.Kic_ = 2.0e4; - parms1.Kpc_ = 15.0; - parms1.Cf_ = 5.0e-5; - parms1.rLf_ = 0.1; - parms1.Lf_ = 1.35e-3; - parms1.rLc_ = 0.03; - parms1.Lc_ = 0.35e-3; - - GridKit::DistributedGeneratorParameters parms2; - // Parameters from MATLAB Microgrid code for first DG - parms2.wb_ = 2.0 * pi * 50.0; - parms2.wc_ = 31.41; - parms2.mp_ = 12.5e-5; - parms2.Vn_ = 380.0; - parms2.nq_ = 1.5e-3; - parms2.F_ = 0.75; - parms2.Kiv_ = 390.0; - parms2.Kpv_ = 0.05; - parms2.Kic_ = 16.0e3; - parms2.Kpc_ = 10.5; - parms2.Cf_ = 50.0e-6; - parms2.rLf_ = 0.1; - parms2.Lf_ = 1.35e-3; - parms2.rLc_ = 0.03; - parms2.Lc_ = 0.35e-3; - - // Line params - double rline1 = 0.23; - double Lline1 = 0.1 / (2.0 * pi * 50.0); - - double rline2 = 0.35; - double Lline2 = 0.58 / (2.0 * pi * 50.0); - - double rline3 = 0.23; - double Lline3 = 0.1 / (2.0 * pi * 50.0); - - // load parms - double rload1 = 3.0; - double Lload1 = 2.0 / (2.0 * pi * 50.0); - - double rload2 = 2.0; - double Lload2 = 1.0 / (2.0 * pi * 50.0); - - using SignalNode = GridKit::PowerElectronics::SignalNode; - SignalNode dg_signal; - - sysmodel->addNode(&dg_signal); - - using Bus = GridKit::PowerElectronics::MicrogridBus; - Bus bus1; - Bus bus2; - Bus bus3; - Bus bus4; - - sysmodel->addNode(&bus1); - sysmodel->addNode(&bus2); - sysmodel->addNode(&bus3); - sysmodel->addNode(&bus4); - - // dg 1 - GridKit::DistributedGenerator* dg1 = new GridKit::DistributedGenerator( - 0, parms1, true, &dg_signal, &bus1); - sysmodel->addComponent(dg1); - - // dg 2 - GridKit::DistributedGenerator* dg2 = new GridKit::DistributedGenerator( - 1, parms1, false, &dg_signal, &bus2); - sysmodel->addComponent(dg2); - - // dg 3 - GridKit::DistributedGenerator* dg3 = new GridKit::DistributedGenerator( - 2, parms2, false, &dg_signal, &bus3); - sysmodel->addComponent(dg3); - - // dg 4 - GridKit::DistributedGenerator* dg4 = new GridKit::DistributedGenerator( - 3, parms2, false, &dg_signal, &bus4); - sysmodel->addComponent(dg4); - - // Lines - - // line 1 - GridKit::MicrogridLine* l1 = new GridKit::MicrogridLine( - 4, rline1, Lline1, &dg_signal, &bus1, &bus2); - sysmodel->addComponent(l1); - - // line 2 - GridKit::MicrogridLine* l2 = new GridKit::MicrogridLine( - 5, rline2, Lline2, &dg_signal, &bus2, &bus3); - sysmodel->addComponent(l2); - - // line 3 - GridKit::MicrogridLine* l3 = new GridKit::MicrogridLine( - 6, rline3, Lline3, &dg_signal, &bus3, &bus4); - sysmodel->addComponent(l3); - - // loads - - // load 1 - GridKit::MicrogridLoad* load1 = new GridKit::MicrogridLoad(7, rload1, Lload1, &dg_signal, &bus1); - sysmodel->addComponent(load1); - - // load 2 - GridKit::MicrogridLoad* load2 = new GridKit::MicrogridLoad(8, rload2, Lload2, &dg_signal, &bus3); - sysmodel->addComponent(load2); - - // Virtual PQ Buses - GridKit::MicrogridBusDQ* bus_para_1 = new GridKit::MicrogridBusDQ(9, RN, &bus1); - sysmodel->addComponent(bus_para_1); - - GridKit::MicrogridBusDQ* bus_para_2 = new GridKit::MicrogridBusDQ(10, RN, &bus2); - sysmodel->addComponent(bus_para_2); - - GridKit::MicrogridBusDQ* bus_para_3 = new GridKit::MicrogridBusDQ(11, RN, &bus3); - sysmodel->addComponent(bus_para_3); - - GridKit::MicrogridBusDQ* bus_para_4 = new GridKit::MicrogridBusDQ(12, RN, &bus4); - sysmodel->addComponent(bus_para_4); + // Build the four-generator microgrid network. + size_t N_size = 2; + GridKit::ScaleMicrogridNetwork network(N_size); + + GridKit::buildScaleMicrogridNetwork(network); + GridKit::assembleSystem(network, *sysmodel); + + // Generator parameters used to construct the initial conditions. + const auto& parms1 = network.DGParam_list[0]; + const auto& parms2 = network.DGParam_list[2]; sysmodel->allocate(); @@ -192,7 +61,7 @@ int main(int /* argc */, char const** /* argv */) } // since the intial P_com = 0 - y[dg_signal.getNodeConnection(0).idx_] = parms1.wb_; + y[network.dg_signal.getNodeConnection(0).idx_] = parms1.wb_; sysmodel->y().setDataUpdated(); sysmodel->yp().setDataUpdated(); diff --git a/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp b/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp new file mode 100644 index 000000000..84bc1b118 --- /dev/null +++ b/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp @@ -0,0 +1,309 @@ +// MicrogridNetwork.hpp + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace GridKit +{ + + using index_type = size_t; + using real_type = double; + + using SignalNode = GridKit::PowerElectronics::SignalNode; + using Bus = GridKit::PowerElectronics::MicrogridBus; + using BusDQ = GridKit::MicrogridBusDQ; + using DGGenerator = GridKit::DistributedGenerator; + using Line = GridKit::MicrogridLine; + using Load = GridKit::MicrogridLoad; + using GenParams = GridKit::DistributedGeneratorParameters; + + /* + * Contains components and nodes that make up the scaled microgrid network. + * + * The network contains 2 * N_size IBRs and stores the physical components + * that make up the scale microgrid. + */ + struct ScaleMicrogridNetwork + { + size_t model_id_next; + size_t N_size; + SignalNode dg_signal; + std::vector buses; + std::vector busesDQ; + std::vector generators; + std::vector lines; + std::vector loads; + std::vector DGParam_list; + + ScaleMicrogridNetwork(size_t n_size) + : model_id_next(0), + N_size(n_size), + buses(2 * n_size), + busesDQ(2 * n_size, nullptr), + generators(2 * n_size, nullptr), + lines(2 * n_size, nullptr), + loads(2 * n_size, nullptr), + DGParam_list(2 * n_size) + { + } + }; + + /** + * @brief Construct all components of a scaled microgrid network. + * + * Builds a microgrid containing @c 2*N_size generators and buses connected + * in a chain by transmission lines. Loads are connected to every other bus, + * and a virtual DQ bus is associated with each physical bus. + * + * The first two generators use the reference generator parameter set, while + * all remaining generators use the second parameter set. Line parameters + * alternate along the network, and the first load uses a different parameter + * set from the remaining loads. + * + * The created components are stored in @p network and assigned unique model + * identifiers using @c network.model_id_next. + * + * @param[in,out] network Network in which the microgrid components are + * constructed and stored. + * + * @pre @c network.N_size is greater than zero. + * @pre The component storage in @p network has been sized consistently with + * @c network.N_size. + * + * @post @p network contains @c 2*N_size generators and virtual DQ buses. + * @post @p network contains @c 2*N_size-1 transmission lines connecting + * consecutive buses. + * @post @p network contains @c N_size loads connected to every other bus. + * @post @c network.DGParam_list contains the parameters associated with each + * generator. + * @post @c network.model_id_next is advanced for every component created. + * + * @note Components are dynamically allocated and their pointers are stored + * in the corresponding network component vectors. + */ + inline void buildScaleMicrogridNetwork(ScaleMicrogridNetwork& network) + { + size_t N_size = network.N_size; + + assert(N_size > 0); + // Every Bus has the same virtual resistance. This is due to numerical stability as mentioned in the paper. + real_type RN = 1.0e4; + + // DG Params Vector + // All DGs have the same set of parameters except for the first two. + GenParams DG_parms1; + DG_parms1.wb_ = 2.0 * M_PI * 50.0; + DG_parms1.wc_ = 31.41; + DG_parms1.mp_ = 9.4e-5; + DG_parms1.Vn_ = 380.0; + DG_parms1.nq_ = 1.3e-3; + DG_parms1.F_ = 0.75; + DG_parms1.Kiv_ = 420.0; + DG_parms1.Kpv_ = 0.1; + DG_parms1.Kic_ = 2.0e4; + DG_parms1.Kpc_ = 15.0; + DG_parms1.Cf_ = 5.0e-5; + DG_parms1.rLf_ = 0.1; + DG_parms1.Lf_ = 1.35e-3; + DG_parms1.rLc_ = 0.03; + DG_parms1.Lc_ = 0.35e-3; + + GenParams DG_parms2; + DG_parms2.wb_ = 2.0 * M_PI * 50.0; + DG_parms2.wc_ = 31.41; + DG_parms2.mp_ = 12.5e-5; + DG_parms2.Vn_ = 380.0; + DG_parms2.nq_ = 1.5e-3; + DG_parms2.F_ = 0.75; + DG_parms2.Kiv_ = 390.0; + DG_parms2.Kpv_ = 0.05; + DG_parms2.Kic_ = 16.0e3; + DG_parms2.Kpc_ = 10.5; + DG_parms2.Cf_ = 50.0e-6; + DG_parms2.rLf_ = 0.1; + DG_parms2.Lf_ = 1.35e-3; + DG_parms2.rLc_ = 0.03; + DG_parms2.Lc_ = 0.35e-3; + + network.DGParam_list.assign(2 * N_size, DG_parms2); + + // First two generators use parameters 1 + if (network.DGParam_list.size() >= 1) + { + network.DGParam_list[0] = DG_parms1; + } + if (network.DGParam_list.size() >= 2) + { + network.DGParam_list[1] = DG_parms1; + } + + // line vector params + // Every odd line has the same parameters and every even line has the same parameters + real_type rline1 = 0.23; + real_type Lline1 = 0.1 / (2.0 * M_PI * 50.0); + real_type rline2 = 0.35; + real_type Lline2 = 0.58 / (2.0 * M_PI * 50.0); + std::vector rline_list(2 * N_size - 1, 0.0); + std::vector Lline_list(2 * N_size - 1, 0.0); + for (index_type i = 0; i < rline_list.size(); i++) + { + rline_list[i] = (i % 2) ? rline2 : rline1; + Lline_list[i] = (i % 2) ? Lline2 : Lline1; + } + + // load parms + // Only the first load has the same paramaters. + real_type rload1 = 3.0; + real_type Lload1 = 2.0 / (2.0 * M_PI * 50.0); + real_type rload2 = 2.0; + real_type Lload2 = 1.0 / (2.0 * M_PI * 50.0); + + std::vector rload_list(N_size, rload2); + std::vector Lload_list(N_size, Lload2); + if (rload_list.size() >= 1) + { + rload_list[0] = rload1; + Lload_list[0] = Lload1; + } + + // Create the reference generator + auto* dg_ref = new DGGenerator(network.model_id_next++, + network.DGParam_list[0], + true, + &network.dg_signal, + &network.buses[0]); + + network.generators[0] = dg_ref; + + // Create the remaining generators. + for (index_type i = 1; i < 2 * N_size; i++) + { + auto* dg = new DGGenerator(network.model_id_next++, + network.DGParam_list[i], + false, + &network.dg_signal, + &network.buses[i]); + + network.generators[i] = dg; + } + + // // Create transmission lines between consecutive buses. + for (index_type i = 0; i < 2 * N_size - 1; i++) + { + auto* line_model = new Line(network.model_id_next++, + rline_list[i], + Lline_list[i], + &network.dg_signal, + &network.buses[i], + &network.buses[i + 1]); + + network.lines[i + 1] = line_model; + } + + // Create loads on every other bus. + for (index_type i = 0; i < N_size; i++) + { + auto* load_model = new Load(network.model_id_next++, + rload_list[i], + Lload_list[i], + &network.dg_signal, + &network.buses[2 * i]); + + network.loads[2 * i] = load_model; + } + + // Create and Add all the microgrid Virtual DQ Buses + for (index_type i = 0; i < 2 * N_size; i++) + { + auto* virDQbus_model = new BusDQ(network.model_id_next++, + RN, + &network.buses[i]); + + network.busesDQ[i] = virDQbus_model; + } + } + + /** + * @brief Assemble a scaled microgrid network into a power electronics model. + * + * Adds the signal node, physical buses, generators, transmission lines, + * loads, and virtual DQ buses stored in @p network to @p sys_model. + * + * This function does not construct or allocate any network components. The + * physical network must already have been created by + * buildScaleMicrogridNetwork(). + * + * @param[in] network Constructed scaled microgrid network whose components + * are added to the system model. + * @param[in,out] sys_model Power electronics model to which the network + * components and nodes are added. + * + * @pre @c network.N_size is greater than zero. + * @pre @p network has been constructed by buildScaleMicrogridNetwork(). + * @pre All component and node pointers referenced by @p network are valid. + * + * @post The signal node and all physical buses in @p network have been added + * to @p sys_model. + * @post All generators, transmission lines, loads, and virtual DQ buses in + * @p network have been added to @p sys_model. + * + * @note This function only assembles the network into the system model. It + * does not call PowerElectronicsModel::allocate(). + */ + inline void assembleSystem(ScaleMicrogridNetwork& network, GridKit::PowerElectronicsModel& sys_model) + { + size_t N_size = network.N_size; + + // Ensure minimum size requirement + assert(N_size > 0); + + // Add all bus nodes + sys_model.addNode(&network.dg_signal); + + for (size_t i = 0; i < 2 * N_size; i++) + { + sys_model.addNode(&network.buses[i]); + } + + // Add all generators + for (index_type i = 0; i < 2 * N_size; i++) + { + sys_model.addComponent(network.generators[i]); + } + + // Load all the Line components + for (index_type i = 1; i < 2 * N_size; i++) + { + sys_model.addComponent(network.lines[i]); + } + + // Load all the Load components + for (index_type i = 0; i < 2 * N_size; i++) + { + if (network.loads[i] != nullptr) + { + sys_model.addComponent(network.loads[i]); + } + } + + // Add all the microgrid Virtual DQ Buses + for (index_type i = 0; i < 2 * N_size; i++) + { + sys_model.addComponent(network.busesDQ[i]); + } + } +} // namespace GridKit diff --git a/examples/PowerElectronics/ScaleMicrogrid/CMakeLists.txt b/examples/PowerElectronics/ScaleMicrogrid/CMakeLists.txt index 0334a939b..6bee549d3 100644 --- a/examples/PowerElectronics/ScaleMicrogrid/CMakeLists.txt +++ b/examples/PowerElectronics/ScaleMicrogrid/CMakeLists.txt @@ -1,5 +1,14 @@ add_executable(scalemicrogrid ScaleMicrogrid.cpp) add_executable(scalemicrogridarbitrary ScaleMicrogridArbitrary.cpp) + +target_include_directories( + scalemicrogrid + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..) + +target_include_directories( + scalemicrogridarbitrary + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..) + target_link_libraries( scalemicrogrid GridKit::power_elec_disgen diff --git a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp index cc8dc28ee..1e97cd56a 100644 --- a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp +++ b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp @@ -1,22 +1,14 @@ #include -#include -#include -#include #include -#include -#include - -#include -#include -#include -#include -#include -#include +#include + #include #include #include #include +#include "Common/MicrogridNetwork.hpp" + using index_type = size_t; using real_type = double; @@ -94,143 +86,11 @@ int test(index_type Nsize, real_type error_tol, bool debug_output) std::cout << "Using default Nsize = 8.\n"; } - // Modeled after the problem in the paper - // Every Bus has the same virtual resistance. This is due to the numerical stability as mentioned in the paper. - real_type RN = 1.0e4; - - // DG Params Vector - // All DGs have the same set of parameters except for the first two. - static constexpr auto pi = std::numbers::pi_v; - - GridKit::DistributedGeneratorParameters DG_parms1; - DG_parms1.wb_ = 2.0 * pi * 50.0; - DG_parms1.wc_ = 31.41; - DG_parms1.mp_ = 9.4e-5; - DG_parms1.Vn_ = 380.0; - DG_parms1.nq_ = 1.3e-3; - DG_parms1.F_ = 0.75; - DG_parms1.Kiv_ = 420.0; - DG_parms1.Kpv_ = 0.1; - DG_parms1.Kic_ = 2.0e4; - DG_parms1.Kpc_ = 15.0; - DG_parms1.Cf_ = 5.0e-5; - DG_parms1.rLf_ = 0.1; - DG_parms1.Lf_ = 1.35e-3; - DG_parms1.rLc_ = 0.03; - DG_parms1.Lc_ = 0.35e-3; - - GridKit::DistributedGeneratorParameters DG_parms2; - DG_parms2.wb_ = 2.0 * pi * 50.0; - DG_parms2.wc_ = 31.41; - DG_parms2.mp_ = 12.5e-5; - DG_parms2.Vn_ = 380.0; - DG_parms2.nq_ = 1.5e-3; - DG_parms2.F_ = 0.75; - DG_parms2.Kiv_ = 390.0; - DG_parms2.Kpv_ = 0.05; - DG_parms2.Kic_ = 16.0e3; - DG_parms2.Kpc_ = 10.5; - DG_parms2.Cf_ = 50.0e-6; - DG_parms2.rLf_ = 0.1; - DG_parms2.Lf_ = 1.35e-3; - DG_parms2.rLc_ = 0.03; - DG_parms2.Lc_ = 0.35e-3; - - std::vector> DGParams_list(2 * Nsize, DG_parms2); - - DGParams_list[0] = DG_parms1; - DGParams_list[1] = DG_parms1; - - // line vector params - // Every odd line has the same parameters and every even line has the same parameters - real_type rline1 = 0.23; - real_type Lline1 = 0.1 / (2.0 * pi * 50.0); - real_type rline2 = 0.35; - real_type Lline2 = 0.58 / (2.0 * pi * 50.0); - std::vector rline_list(2 * Nsize - 1, 0.0); - std::vector Lline_list(2 * Nsize - 1, 0.0); - for (index_type i = 0; i < rline_list.size(); i++) - { - rline_list[i] = (i % 2) ? rline2 : rline1; - Lline_list[i] = (i % 2) ? Lline2 : Lline1; - } - - // load parms - // Only the first load has the same paramaters. - real_type rload1 = 3.0; - real_type Lload1 = 2.0 / (2.0 * pi * 50.0); - real_type rload2 = 2.0; - real_type Lload2 = 1.0 / (2.0 * pi * 50.0); - - std::vector rload_list(Nsize, rload2); - std::vector Lload_list(Nsize, Lload2); - rload_list[0] = rload1; - Lload_list[0] = Lload1; - - using SignalNode = GridKit::PowerElectronics::SignalNode; - SignalNode dg_signal; - sys_model->addNode(&dg_signal); - - using Bus = GridKit::PowerElectronics::MicrogridBus; - std::unique_ptr[]> buses = std::make_unique[]>(2 * Nsize); - for (size_t i = 0; i < 2 * Nsize; i++) - { - buses[i] = std::make_unique(); - sys_model->addNode(buses[i].get()); - } - - // Create the reference DG - auto* dg_ref = new DistributedGenerator(0, - DGParams_list[0], - true, - &dg_signal, - buses[0].get()); - sys_model->addComponent(dg_ref); - - // Keep track of models and index location - index_type model_id = 1; - // Add all other DGs - for (index_type i = 1; i < 2 * Nsize; i++) - { - // current DG to add - auto* dg = new DistributedGenerator(model_id++, - DGParams_list[i], - false, - &dg_signal, - buses[i].get()); - sys_model->addComponent(dg); - } - - // Load all the Line compoenents - for (index_type i = 0; i < 2 * Nsize - 1; i++) - { - // line - auto* line_model = new MicrogridLine(model_id++, - rline_list[i], - Lline_list[i], - &dg_signal, - buses[i].get(), - buses[i + 1].get()); - sys_model->addComponent(line_model); - } - - // Load all the Load components - for (index_type i = 0; i < Nsize; i++) - { - auto* load_model = new MicrogridLoad(model_id++, - rload_list[i], - Lload_list[i], - &dg_signal, - buses[2 * i].get()); - sys_model->addComponent(load_model); - } + // Build and assemble the scaled microgrid network. + ScaleMicrogridNetwork network(Nsize); - // Add all the microgrid Virtual DQ Buses - for (index_type i = 0; i < 2 * Nsize; i++) - { - auto* virDQbus_model = new MicrogridBusDQ(model_id++, RN, buses[i].get()); - sys_model->addComponent(virDQbus_model); - } + buildScaleMicrogridNetwork(network); + assembleSystem(network, *sys_model); // allocate all the intial conditions sys_model->allocate(); @@ -253,13 +113,15 @@ int test(index_type Nsize, real_type error_tol, bool debug_output) // Create initial derivatives specifics generated in MATLAB for (index_type i = 0; i < 2 * Nsize; i++) { - yp[13 * i - 1 + 2] = DGParams_list[i].Vn_; - yp[13 * i - 1 + 4] = DGParams_list[i].Kpv_ * DGParams_list[i].Vn_; - yp[13 * i - 1 + 6] = (DGParams_list[i].Kpc_ * DGParams_list[i].Kpv_ * DGParams_list[i].Vn_) / DGParams_list[i].Lf_; + const auto& params = network.DGParam_list[i]; + + yp[13 * i - 1 + 2] = params.Vn_; + yp[13 * i - 1 + 4] = params.Kpv_ * params.Vn_; + yp[13 * i - 1 + 6] = (params.Kpc_ * params.Kpv_ * params.Vn_) / params.Lf_; } // since the intial P_com = 0, the set the intial vector to the reference frame - y[dg_signal.getNodeConnection(0).idx_] = DG_parms1.wb_; + y[network.dg_signal.getNodeConnection(0).idx_] = network.DGParam_list[0].wb_; sys_model->y().setDataUpdated(); sys_model->yp().setDataUpdated(); diff --git a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp index a8ab6a4a1..c83ce2979 100644 --- a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp +++ b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp @@ -1,20 +1,13 @@ #include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include #include #include #include #include +#include "Common/MicrogridNetwork.hpp" + using index_type = size_t; using real_type = double; @@ -79,149 +72,11 @@ int printMicrogridSystems(index_type N_size) return 1; } - // Modeled after the problem in the paper - // Every Bus has the same virtual resistance. This is due to numerical stability as mentioned in the paper. - real_type RN = 1.0e4; - - // DG Params Vector - // All DGs have the same set of parameters except for the first two. - static constexpr auto pi = std::numbers::pi_v; - - GridKit::DistributedGeneratorParameters DG_parms1; - DG_parms1.wb_ = 2.0 * pi * 50.0; - DG_parms1.wc_ = 31.41; - DG_parms1.mp_ = 9.4e-5; - DG_parms1.Vn_ = 380.0; - DG_parms1.nq_ = 1.3e-3; - DG_parms1.F_ = 0.75; - DG_parms1.Kiv_ = 420.0; - DG_parms1.Kpv_ = 0.1; - DG_parms1.Kic_ = 2.0e4; - DG_parms1.Kpc_ = 15.0; - DG_parms1.Cf_ = 5.0e-5; - DG_parms1.rLf_ = 0.1; - DG_parms1.Lf_ = 1.35e-3; - DG_parms1.rLc_ = 0.03; - DG_parms1.Lc_ = 0.35e-3; - - GridKit::DistributedGeneratorParameters DG_parms2; - DG_parms2.wb_ = 2.0 * pi * 50.0; - DG_parms2.wc_ = 31.41; - DG_parms2.mp_ = 12.5e-5; - DG_parms2.Vn_ = 380.0; - DG_parms2.nq_ = 1.5e-3; - DG_parms2.F_ = 0.75; - DG_parms2.Kiv_ = 390.0; - DG_parms2.Kpv_ = 0.05; - DG_parms2.Kic_ = 16.0e3; - DG_parms2.Kpc_ = 10.5; - DG_parms2.Cf_ = 50.0e-6; - DG_parms2.rLf_ = 0.1; - DG_parms2.Lf_ = 1.35e-3; - DG_parms2.rLc_ = 0.03; - DG_parms2.Lc_ = 0.35e-3; - - std::vector> DGParams_list(2 * N_size, DG_parms2); - - // First two generators use parameters 1 - if (DGParams_list.size() >= 1) - DGParams_list[0] = DG_parms1; - if (DGParams_list.size() >= 2) - DGParams_list[1] = DG_parms1; - - // line vector params - // Every odd line has the same parameters and every even line has the same parameters - real_type rline1 = 0.23; - real_type Lline1 = 0.1 / (2.0 * pi * 50.0); - real_type rline2 = 0.35; - real_type Lline2 = 0.58 / (2.0 * pi * 50.0); - std::vector rline_list(2 * N_size - 1, 0.0); - std::vector Lline_list(2 * N_size - 1, 0.0); - for (index_type i = 0; i < rline_list.size(); i++) - { - rline_list[i] = (i % 2) ? rline2 : rline1; - Lline_list[i] = (i % 2) ? Lline2 : Lline1; - } - - // load parms - // Only the first load has the same paramaters. - real_type rload1 = 3.0; - real_type Lload1 = 2.0 / (2.0 * pi * 50.0); - real_type rload2 = 2.0; - real_type Lload2 = 1.0 / (2.0 * pi * 50.0); - - std::vector rload_list(N_size, rload2); - std::vector Lload_list(N_size, Lload2); - if (rload_list.size() >= 1) - { - rload_list[0] = rload1; - Lload_list[0] = Lload1; - } - - using SignalNode = GridKit::PowerElectronics::SignalNode; - SignalNode dg_signal; - sys_model.addNode(&dg_signal); + // Build and assemble the scaled microgrid network. + ScaleMicrogridNetwork network(N_size); - using Bus = GridKit::PowerElectronics::MicrogridBus; - std::unique_ptr[]> buses = std::make_unique[]>(2 * N_size); - for (size_t i = 0; i < 2 * N_size; i++) - { - buses[i] = std::make_unique(); - sys_model.addNode(buses[i].get()); - } - - // Create the reference DG - auto* dg_ref = new DistributedGenerator(0, - DGParams_list[0], - true, - &dg_signal, - buses[0].get()); - sys_model.addComponent(dg_ref); - - // Keep track of models and index location - index_type model_id = 1; - // Add all other DGs - for (index_type i = 1; i < 2 * N_size; i++) - { - // current DG to add - auto* dg = new DistributedGenerator(model_id++, - DGParams_list[i], - false, - &dg_signal, - buses[i].get()); - sys_model.addComponent(dg); - } - - // Load all the Line components - for (index_type i = 0; i < 2 * N_size - 1; i++) - { - // line - auto* line_model = new MicrogridLine(model_id++, - rline_list[i], - Lline_list[i], - &dg_signal, - buses[i].get(), - buses[i + 1].get()); - sys_model.addComponent(line_model); - } - - // Load all the Load components - for (index_type i = 0; i < N_size; i++) - { - auto* load_model = new MicrogridLoad(model_id++, - rload_list[i], - Lload_list[i], - &dg_signal, - buses[2 * i].get()); - sys_model.addComponent(load_model); - } - - // Add all the microgrid Virtual DQ Buses - for (index_type i = 0; i < 2 * N_size; i++) - { - auto* virDQbus_model = new MicrogridBusDQ(model_id++, RN, buses[i].get()); - sys_model.addComponent(virDQbus_model); - } + buildScaleMicrogridNetwork(network); + assembleSystem(network, sys_model); // allocate all the initial conditions sys_model.allocate(); @@ -236,16 +91,22 @@ int printMicrogridSystems(index_type N_size) yp[i] = 0.0; } + //------------------------------------------------------------------- // Create Initial derivatives specifics generated in MATLAB + //------------------------------------------------------------------- for (index_type i = 0; i < 2 * N_size; i++) { - yp[13 * i - 1 + 3] = DGParams_list[i].Vn_; - yp[13 * i - 1 + 5] = DGParams_list[i].Kpv_ * DGParams_list[i].Vn_; - yp[13 * i - 1 + 7] = (DGParams_list[i].Kpc_ * DGParams_list[i].Kpv_ * DGParams_list[i].Vn_) / DGParams_list[i].Lf_; + const auto& params = network.DGParam_list[i]; + + yp[13 * i - 1 + 3] = params.Vn_; + yp[13 * i - 1 + 5] = params.Kpv_ * params.Vn_; + yp[13 * i - 1 + 7] = (params.Kpc_ * params.Kpv_ * params.Vn_) / params.Lf_; } + //--------------------------------------------------------------------------- // since the initial P_com = 0, set the initial vector to the reference frame - y[dg_signal.getNodeConnection(0).idx_] = DG_parms1.wb_; + //--------------------------------------------------------------------------- + y[network.dg_signal.getNodeConnection(0).idx_] = network.DGParam_list[0].wb_; sys_model.y().setDataUpdated(); sys_model.yp().setDataUpdated(); From e73c8c0ad670197b7d67d9125b4d8dc59a3a245b Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Wed, 26 Aug 2026 08:39:34 +0000 Subject: [PATCH 03/10] Fixed include path for microgrid examples --- examples/PowerElectronics/Microgrid/Microgrid.cpp | 2 +- .../PowerElectronicsExamplesHelper/MicrogridNetwork.hpp | 2 -- examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp | 2 +- .../ScaleMicrogrid/ScaleMicrogridArbitrary.cpp | 3 +-- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/examples/PowerElectronics/Microgrid/Microgrid.cpp b/examples/PowerElectronics/Microgrid/Microgrid.cpp index e20d9e5ac..86801715a 100644 --- a/examples/PowerElectronics/Microgrid/Microgrid.cpp +++ b/examples/PowerElectronics/Microgrid/Microgrid.cpp @@ -6,7 +6,7 @@ #include #include -#include "Common/MicrogridNetwork.hpp" +#include "PowerElectronicsExamplesHelper/MicrogridNetwork.hpp" int main(int /* argc */, char const** /* argv */) { diff --git a/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp b/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp index 84bc1b118..ada31a098 100644 --- a/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp +++ b/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp @@ -13,8 +13,6 @@ #include #include #include -#include -#include #include namespace GridKit diff --git a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp index 1e97cd56a..fd8d5ecfd 100644 --- a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp +++ b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp @@ -7,7 +7,7 @@ #include #include -#include "Common/MicrogridNetwork.hpp" +#include "PowerElectronicsExamplesHelper/MicrogridNetwork.hpp" using index_type = size_t; using real_type = double; diff --git a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp index c83ce2979..03e2f7891 100644 --- a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp +++ b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp @@ -1,12 +1,11 @@ #include #include -#include #include #include #include -#include "Common/MicrogridNetwork.hpp" +#include "PowerElectronicsExamplesHelper/MicrogridNetwork.hpp" using index_type = size_t; using real_type = double; From 6496df47705aa70e7d0920b95030311c7e1913d6 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Thu, 27 Aug 2026 19:21:23 +0000 Subject: [PATCH 04/10] Minor update to MicrogridNetwork.hpp implementation and microgrid examples --- .../PowerElectronics/Microgrid/Microgrid.cpp | 8 +- .../MicrogridNetwork.hpp | 296 +++++++++--------- .../ScaleMicrogrid/ScaleMicrogrid.cpp | 4 +- .../ScaleMicrogridArbitrary.cpp | 4 +- 4 files changed, 151 insertions(+), 161 deletions(-) diff --git a/examples/PowerElectronics/Microgrid/Microgrid.cpp b/examples/PowerElectronics/Microgrid/Microgrid.cpp index 86801715a..4f657dcf3 100644 --- a/examples/PowerElectronics/Microgrid/Microgrid.cpp +++ b/examples/PowerElectronics/Microgrid/Microgrid.cpp @@ -21,11 +21,9 @@ int main(int /* argc */, char const** /* argv */) auto* sysmodel = new GridKit::PowerElectronicsModel(use_jac); // Build the four-generator microgrid network. - size_t N_size = 2; - GridKit::ScaleMicrogridNetwork network(N_size); - - GridKit::buildScaleMicrogridNetwork(network); - GridKit::assembleSystem(network, *sysmodel); + size_t N_size = 2; + ScaleMicrogridNetwork network(N_size); + assembleSystem(network, *sysmodel); // Generator parameters used to construct the initial conditions. const auto& parms1 = network.DGParam_list[0]; diff --git a/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp b/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp index ada31a098..0ee1894fb 100644 --- a/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp +++ b/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp @@ -15,50 +15,46 @@ #include #include -namespace GridKit +/* + * Contains components and nodes that make up the scaled microgrid network. + * + * The network contains 2 * N_size IBRs and stores the physical components + * that make up the scale microgrid. + */ +template +struct ScaleMicrogridNetwork { - using index_type = size_t; - using real_type = double; - - using SignalNode = GridKit::PowerElectronics::SignalNode; - using Bus = GridKit::PowerElectronics::MicrogridBus; - using BusDQ = GridKit::MicrogridBusDQ; - using DGGenerator = GridKit::DistributedGenerator; - using Line = GridKit::MicrogridLine; - using Load = GridKit::MicrogridLoad; - using GenParams = GridKit::DistributedGeneratorParameters; - - /* - * Contains components and nodes that make up the scaled microgrid network. - * - * The network contains 2 * N_size IBRs and stores the physical components - * that make up the scale microgrid. - */ - struct ScaleMicrogridNetwork + using SignalNode = GridKit::PowerElectronics::SignalNode; + using Bus = GridKit::PowerElectronics::MicrogridBus; + using BusDQ = GridKit::MicrogridBusDQ; + using DGGenerator = GridKit::DistributedGenerator; + using Line = GridKit::MicrogridLine; + using Load = GridKit::MicrogridLoad; + using GenParams = GridKit::DistributedGeneratorParameters; + + size_t model_id_next; + size_t N_size; + SignalNode dg_signal; + std::vector buses; + std::vector busesDQ; + std::vector generators; + std::vector lines; + std::vector loads; + std::vector DGParam_list; + + ScaleMicrogridNetwork(size_t n_size) + : model_id_next(0), + N_size(n_size), + buses(2 * n_size), + busesDQ(2 * n_size, nullptr), + generators(2 * n_size, nullptr), + lines(2 * n_size, nullptr), + loads(2 * n_size, nullptr), + DGParam_list(2 * n_size) { - size_t model_id_next; - size_t N_size; - SignalNode dg_signal; - std::vector buses; - std::vector busesDQ; - std::vector generators; - std::vector lines; - std::vector loads; - std::vector DGParam_list; - - ScaleMicrogridNetwork(size_t n_size) - : model_id_next(0), - N_size(n_size), - buses(2 * n_size), - busesDQ(2 * n_size, nullptr), - generators(2 * n_size, nullptr), - lines(2 * n_size, nullptr), - loads(2 * n_size, nullptr), - DGParam_list(2 * n_size) - { - } - }; + buildScaleMicrogridNetwork(); + } /** * @brief Construct all components of a scaled microgrid network. @@ -93,14 +89,13 @@ namespace GridKit * @note Components are dynamically allocated and their pointers are stored * in the corresponding network component vectors. */ - inline void buildScaleMicrogridNetwork(ScaleMicrogridNetwork& network) + void buildScaleMicrogridNetwork() { - size_t N_size = network.N_size; - assert(N_size > 0); // Every Bus has the same virtual resistance. This is due to numerical stability as mentioned in the paper. - real_type RN = 1.0e4; + ScalarT RN = 1.0e4; + // TODO: add this as parameters // DG Params Vector // All DGs have the same set of parameters except for the first two. GenParams DG_parms1; @@ -137,27 +132,27 @@ namespace GridKit DG_parms2.rLc_ = 0.03; DG_parms2.Lc_ = 0.35e-3; - network.DGParam_list.assign(2 * N_size, DG_parms2); + DGParam_list.assign(2 * N_size, DG_parms2); // First two generators use parameters 1 - if (network.DGParam_list.size() >= 1) + if (DGParam_list.size() >= 1) { - network.DGParam_list[0] = DG_parms1; + DGParam_list[0] = DG_parms1; } - if (network.DGParam_list.size() >= 2) + if (DGParam_list.size() >= 2) { - network.DGParam_list[1] = DG_parms1; + DGParam_list[1] = DG_parms1; } // line vector params // Every odd line has the same parameters and every even line has the same parameters - real_type rline1 = 0.23; - real_type Lline1 = 0.1 / (2.0 * M_PI * 50.0); - real_type rline2 = 0.35; - real_type Lline2 = 0.58 / (2.0 * M_PI * 50.0); - std::vector rline_list(2 * N_size - 1, 0.0); - std::vector Lline_list(2 * N_size - 1, 0.0); - for (index_type i = 0; i < rline_list.size(); i++) + ScalarT rline1 = 0.23; + ScalarT Lline1 = 0.1 / (2.0 * M_PI * 50.0); + ScalarT rline2 = 0.35; + ScalarT Lline2 = 0.58 / (2.0 * M_PI * 50.0); + std::vector rline_list(2 * N_size - 1, 0.0); + std::vector Lline_list(2 * N_size - 1, 0.0); + for (IdxT i = 0; i < rline_list.size(); i++) { rline_list[i] = (i % 2) ? rline2 : rline1; Lline_list[i] = (i % 2) ? Lline2 : Lline1; @@ -165,13 +160,13 @@ namespace GridKit // load parms // Only the first load has the same paramaters. - real_type rload1 = 3.0; - real_type Lload1 = 2.0 / (2.0 * M_PI * 50.0); - real_type rload2 = 2.0; - real_type Lload2 = 1.0 / (2.0 * M_PI * 50.0); + ScalarT rload1 = 3.0; + ScalarT Lload1 = 2.0 / (2.0 * M_PI * 50.0); + ScalarT rload2 = 2.0; + ScalarT Lload2 = 1.0 / (2.0 * M_PI * 50.0); - std::vector rload_list(N_size, rload2); - std::vector Lload_list(N_size, Lload2); + std::vector rload_list(N_size, rload2); + std::vector Lload_list(N_size, Lload2); if (rload_list.size() >= 1) { rload_list[0] = rload1; @@ -179,129 +174,130 @@ namespace GridKit } // Create the reference generator - auto* dg_ref = new DGGenerator(network.model_id_next++, - network.DGParam_list[0], + auto* dg_ref = new DGGenerator(model_id_next++, + DGParam_list[0], true, - &network.dg_signal, - &network.buses[0]); + &dg_signal, + &buses[0]); - network.generators[0] = dg_ref; + generators[0] = dg_ref; // Create the remaining generators. - for (index_type i = 1; i < 2 * N_size; i++) + for (IdxT i = 1; i < 2 * N_size; i++) { - auto* dg = new DGGenerator(network.model_id_next++, - network.DGParam_list[i], + auto* dg = new DGGenerator(model_id_next++, + DGParam_list[i], false, - &network.dg_signal, - &network.buses[i]); + &dg_signal, + &buses[i]); - network.generators[i] = dg; + generators[i] = dg; } // // Create transmission lines between consecutive buses. - for (index_type i = 0; i < 2 * N_size - 1; i++) + for (IdxT i = 0; i < 2 * N_size - 1; i++) { - auto* line_model = new Line(network.model_id_next++, + auto* line_model = new Line(model_id_next++, rline_list[i], Lline_list[i], - &network.dg_signal, - &network.buses[i], - &network.buses[i + 1]); + &dg_signal, + &buses[i], + &buses[i + 1]); - network.lines[i + 1] = line_model; + lines[i + 1] = line_model; } // Create loads on every other bus. - for (index_type i = 0; i < N_size; i++) + for (IdxT i = 0; i < N_size; i++) { - auto* load_model = new Load(network.model_id_next++, + auto* load_model = new Load(model_id_next++, rload_list[i], Lload_list[i], - &network.dg_signal, - &network.buses[2 * i]); + &dg_signal, + &buses[2 * i]); - network.loads[2 * i] = load_model; + loads[2 * i] = load_model; } // Create and Add all the microgrid Virtual DQ Buses - for (index_type i = 0; i < 2 * N_size; i++) + for (IdxT i = 0; i < 2 * N_size; i++) { - auto* virDQbus_model = new BusDQ(network.model_id_next++, + auto* virDQbus_model = new BusDQ(model_id_next++, RN, - &network.buses[i]); + &buses[i]); - network.busesDQ[i] = virDQbus_model; + busesDQ[i] = virDQbus_model; } } +}; + +/** + * @brief Assemble a scaled microgrid network into a power electronics model. + * + * Adds the signal node, physical buses, generators, transmission lines, + * loads, and virtual DQ buses stored in @p network to @p sys_model. + * + * This function does not construct or allocate any network components. The + * physical network must already have been created by + * buildScaleMicrogridNetwork(). + * + * @param[in] network Constructed scaled microgrid network whose components + * are added to the system model. + * @param[in,out] sys_model Power electronics model to which the network + * components and nodes are added. + * + * @pre @c network.N_size is greater than zero. + * @pre @p network has been constructed by buildScaleMicrogridNetwork(). + * @pre All component and node pointers referenced by @p network are valid. + * + * @post The signal node and all physical buses in @p network have been added + * to @p sys_model. + * @post All generators, transmission lines, loads, and virtual DQ buses in + * @p network have been added to @p sys_model. + * + * @note This function only assembles the network into the system model. It + * does not call PowerElectronicsModel::allocate(). + */ +template +void assembleSystem(ScaleMicrogridNetwork& network, GridKit::PowerElectronicsModel& sys_model) +{ + size_t N_size = network.N_size; - /** - * @brief Assemble a scaled microgrid network into a power electronics model. - * - * Adds the signal node, physical buses, generators, transmission lines, - * loads, and virtual DQ buses stored in @p network to @p sys_model. - * - * This function does not construct or allocate any network components. The - * physical network must already have been created by - * buildScaleMicrogridNetwork(). - * - * @param[in] network Constructed scaled microgrid network whose components - * are added to the system model. - * @param[in,out] sys_model Power electronics model to which the network - * components and nodes are added. - * - * @pre @c network.N_size is greater than zero. - * @pre @p network has been constructed by buildScaleMicrogridNetwork(). - * @pre All component and node pointers referenced by @p network are valid. - * - * @post The signal node and all physical buses in @p network have been added - * to @p sys_model. - * @post All generators, transmission lines, loads, and virtual DQ buses in - * @p network have been added to @p sys_model. - * - * @note This function only assembles the network into the system model. It - * does not call PowerElectronicsModel::allocate(). - */ - inline void assembleSystem(ScaleMicrogridNetwork& network, GridKit::PowerElectronicsModel& sys_model) - { - size_t N_size = network.N_size; - - // Ensure minimum size requirement - assert(N_size > 0); + // Ensure minimum size requirement + assert(N_size > 0); - // Add all bus nodes - sys_model.addNode(&network.dg_signal); + // Add all bus nodes + sys_model.addNode(&network.dg_signal); - for (size_t i = 0; i < 2 * N_size; i++) - { - sys_model.addNode(&network.buses[i]); - } + for (size_t i = 0; i < 2 * N_size; i++) + { + sys_model.addNode(&network.buses[i]); + } - // Add all generators - for (index_type i = 0; i < 2 * N_size; i++) - { - sys_model.addComponent(network.generators[i]); - } + // Add all generators + for (IdxT i = 0; i < 2 * N_size; i++) + { + sys_model.addComponent(network.generators[i]); + } - // Load all the Line components - for (index_type i = 1; i < 2 * N_size; i++) - { - sys_model.addComponent(network.lines[i]); - } + // Load all the Line components + for (IdxT i = 1; i < 2 * N_size; i++) + { + sys_model.addComponent(network.lines[i]); + } - // Load all the Load components - for (index_type i = 0; i < 2 * N_size; i++) + // Load all the Load components + for (IdxT i = 0; i < 2 * N_size; i++) + { + if (network.loads[i] != nullptr) { - if (network.loads[i] != nullptr) - { - sys_model.addComponent(network.loads[i]); - } + sys_model.addComponent(network.loads[i]); } + } - // Add all the microgrid Virtual DQ Buses - for (index_type i = 0; i < 2 * N_size; i++) - { - sys_model.addComponent(network.busesDQ[i]); - } + // Add all the microgrid Virtual DQ Buses + for (IdxT i = 0; i < 2 * N_size; i++) + { + sys_model.addComponent(network.busesDQ[i]); } -} // namespace GridKit +} \ No newline at end of file diff --git a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp index fd8d5ecfd..a277c0e42 100644 --- a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp +++ b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp @@ -87,9 +87,7 @@ int test(index_type Nsize, real_type error_tol, bool debug_output) } // Build and assemble the scaled microgrid network. - ScaleMicrogridNetwork network(Nsize); - - buildScaleMicrogridNetwork(network); + ScaleMicrogridNetwork network(Nsize); assembleSystem(network, *sys_model); // allocate all the intial conditions diff --git a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp index 03e2f7891..dd94713f4 100644 --- a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp +++ b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp @@ -72,9 +72,7 @@ int printMicrogridSystems(index_type N_size) } // Build and assemble the scaled microgrid network. - ScaleMicrogridNetwork network(N_size); - - buildScaleMicrogridNetwork(network); + ScaleMicrogridNetwork network(N_size); assembleSystem(network, sys_model); // allocate all the initial conditions From 9821124784dbe375db8bab01ec9c8adb3c48f1ed Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Thu, 27 Aug 2026 19:23:04 +0000 Subject: [PATCH 05/10] Apply pre-commit fixes --- .../PowerElectronicsExamplesHelper/MicrogridNetwork.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp b/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp index 0ee1894fb..f9c642ac3 100644 --- a/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp +++ b/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp @@ -300,4 +300,4 @@ void assembleSystem(ScaleMicrogridNetwork& network, GridKit::Powe { sys_model.addComponent(network.busesDQ[i]); } -} \ No newline at end of file +} From bc76ded847ae7730076dfa107d8b1bbae9b0efe1 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Fri, 28 Aug 2026 00:05:36 +0000 Subject: [PATCH 06/10] Update comments and grid network builder --- .../PowerElectronics/Microgrid/Microgrid.cpp | 4 +- .../MicrogridNetwork.hpp | 41 ++++++++----------- 2 files changed, 18 insertions(+), 27 deletions(-) diff --git a/examples/PowerElectronics/Microgrid/Microgrid.cpp b/examples/PowerElectronics/Microgrid/Microgrid.cpp index 4f657dcf3..828145988 100644 --- a/examples/PowerElectronics/Microgrid/Microgrid.cpp +++ b/examples/PowerElectronics/Microgrid/Microgrid.cpp @@ -95,7 +95,7 @@ int main(int /* argc */, char const** /* argv */) bool all_internal_diff = true; bool all_external_alg = true; - const size_t num_node_vars = bus1.size() + bus2.size() + bus3.size() + bus4.size() + dg_signal.size(); + const size_t num_node_vars = network.buses[0].size() + network.buses[1].size() + network.buses[2].size() + network.buses[3].size() + network.dg_signal.size(); for (size_t i = 0; i < sysmodel->size() - num_node_vars; i++) { @@ -242,4 +242,4 @@ int main(int /* argc */, char const** /* argv */) delete sysmodel; return 0; -} +} \ No newline at end of file diff --git a/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp b/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp index f9c642ac3..35e1c63f3 100644 --- a/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp +++ b/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp @@ -49,7 +49,7 @@ struct ScaleMicrogridNetwork buses(2 * n_size), busesDQ(2 * n_size, nullptr), generators(2 * n_size, nullptr), - lines(2 * n_size, nullptr), + lines(2 * n_size - 1, nullptr), loads(2 * n_size, nullptr), DGParam_list(2 * n_size) { @@ -57,7 +57,7 @@ struct ScaleMicrogridNetwork } /** - * @brief Construct all components of a scaled microgrid network. + * @brief Construct all components of the scaled microgrid network. * * Builds a microgrid containing @c 2*N_size generators and buses connected * in a chain by transmission lines. Loads are connected to every other bus, @@ -68,26 +68,20 @@ struct ScaleMicrogridNetwork * alternate along the network, and the first load uses a different parameter * set from the remaining loads. * - * The created components are stored in @p network and assigned unique model - * identifiers using @c network.model_id_next. + * The created components are stored in this network and assigned unique model + * identifiers using @c model_id_next. * - * @param[in,out] network Network in which the microgrid components are - * constructed and stored. + * @pre @c N_size is greater than zero. * - * @pre @c network.N_size is greater than zero. - * @pre The component storage in @p network has been sized consistently with - * @c network.N_size. - * - * @post @p network contains @c 2*N_size generators and virtual DQ buses. - * @post @p network contains @c 2*N_size-1 transmission lines connecting + * @post The network contains @c 2*N_size generators and virtual DQ buses. + * @post The network contains @c 2*N_size-1 transmission lines connecting * consecutive buses. - * @post @p network contains @c N_size loads connected to every other bus. - * @post @c network.DGParam_list contains the parameters associated with each - * generator. - * @post @c network.model_id_next is advanced for every component created. + * @post The network contains @c N_size loads connected to every other bus. + * @post @c DGParam_list contains the parameters associated with each generator. + * @post @c model_id_next is advanced for every component created. * * @note Components are dynamically allocated and their pointers are stored - * in the corresponding network component vectors. + * in the corresponding component vectors. */ void buildScaleMicrogridNetwork() { @@ -194,7 +188,7 @@ struct ScaleMicrogridNetwork generators[i] = dg; } - // // Create transmission lines between consecutive buses. + // Create transmission lines between consecutive buses. for (IdxT i = 0; i < 2 * N_size - 1; i++) { auto* line_model = new Line(model_id_next++, @@ -204,7 +198,7 @@ struct ScaleMicrogridNetwork &buses[i], &buses[i + 1]); - lines[i + 1] = line_model; + lines[i] = line_model; } // Create loads on every other bus. @@ -237,9 +231,7 @@ struct ScaleMicrogridNetwork * Adds the signal node, physical buses, generators, transmission lines, * loads, and virtual DQ buses stored in @p network to @p sys_model. * - * This function does not construct or allocate any network components. The - * physical network must already have been created by - * buildScaleMicrogridNetwork(). + * This function does not construct or allocate any network components. * * @param[in] network Constructed scaled microgrid network whose components * are added to the system model. @@ -247,7 +239,6 @@ struct ScaleMicrogridNetwork * components and nodes are added. * * @pre @c network.N_size is greater than zero. - * @pre @p network has been constructed by buildScaleMicrogridNetwork(). * @pre All component and node pointers referenced by @p network are valid. * * @post The signal node and all physical buses in @p network have been added @@ -281,7 +272,7 @@ void assembleSystem(ScaleMicrogridNetwork& network, GridKit::Powe } // Load all the Line components - for (IdxT i = 1; i < 2 * N_size; i++) + for (IdxT i = 0; i < 2 * N_size - 1; i++) { sys_model.addComponent(network.lines[i]); } @@ -300,4 +291,4 @@ void assembleSystem(ScaleMicrogridNetwork& network, GridKit::Powe { sys_model.addComponent(network.busesDQ[i]); } -} +} \ No newline at end of file From e7d602b43ca158608ff1fddf04983c7a57c8864f Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Fri, 28 Aug 2026 00:06:51 +0000 Subject: [PATCH 07/10] Apply pre-commit fixes --- examples/PowerElectronics/Microgrid/Microgrid.cpp | 2 +- .../PowerElectronicsExamplesHelper/MicrogridNetwork.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/PowerElectronics/Microgrid/Microgrid.cpp b/examples/PowerElectronics/Microgrid/Microgrid.cpp index 828145988..6513d74ac 100644 --- a/examples/PowerElectronics/Microgrid/Microgrid.cpp +++ b/examples/PowerElectronics/Microgrid/Microgrid.cpp @@ -242,4 +242,4 @@ int main(int /* argc */, char const** /* argv */) delete sysmodel; return 0; -} \ No newline at end of file +} diff --git a/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp b/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp index 35e1c63f3..d7da59762 100644 --- a/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp +++ b/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp @@ -291,4 +291,4 @@ void assembleSystem(ScaleMicrogridNetwork& network, GridKit::Powe { sys_model.addComponent(network.busesDQ[i]); } -} \ No newline at end of file +} From a9f1847e74d26bf18c4427d940bf37a56c46a00d Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Fri, 28 Aug 2026 19:18:22 +0000 Subject: [PATCH 08/10] Update cmake files and examples --- examples/PowerElectronics/CMakeLists.txt | 1 + examples/PowerElectronics/Microgrid/CMakeLists.txt | 7 ++----- examples/PowerElectronics/Microgrid/Microgrid.cpp | 2 +- .../PowerElectronicsExamplesHelper/CMakeLists.txt | 10 ++++++++++ .../PowerElectronics/ScaleMicrogrid/CMakeLists.txt | 14 ++++---------- .../ScaleMicrogrid/ScaleMicrogrid.cpp | 2 +- .../ScaleMicrogrid/ScaleMicrogridArbitrary.cpp | 2 +- 7 files changed, 20 insertions(+), 18 deletions(-) create mode 100644 examples/PowerElectronics/PowerElectronicsExamplesHelper/CMakeLists.txt diff --git a/examples/PowerElectronics/CMakeLists.txt b/examples/PowerElectronics/CMakeLists.txt index 2bf311e22..920e63e46 100644 --- a/examples/PowerElectronics/CMakeLists.txt +++ b/examples/PowerElectronics/CMakeLists.txt @@ -3,6 +3,7 @@ # - Slaven Peles #]] +add_subdirectory(PowerElectronicsExamplesHelper) add_subdirectory(DistributedGeneratorTest) if(TARGET SUNDIALS::idas) diff --git a/examples/PowerElectronics/Microgrid/CMakeLists.txt b/examples/PowerElectronics/Microgrid/CMakeLists.txt index 86dea6678..a919cd9cc 100644 --- a/examples/PowerElectronics/Microgrid/CMakeLists.txt +++ b/examples/PowerElectronics/Microgrid/CMakeLists.txt @@ -1,16 +1,13 @@ add_executable(microgrid Microgrid.cpp) -target_include_directories( - microgrid - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..) - target_link_libraries( microgrid GridKit::power_elec_disgen GridKit::power_elec_microline GridKit::power_elec_microload GridKit::solvers_dyn - GridKit::power_elec_microbusdq) + GridKit::power_elec_microbusdq + GridKit::power_elec_microgrid_network) add_test(NAME Microgrid COMMAND $) install(TARGETS microgrid RUNTIME DESTINATION bin) diff --git a/examples/PowerElectronics/Microgrid/Microgrid.cpp b/examples/PowerElectronics/Microgrid/Microgrid.cpp index 6513d74ac..cf828bf2d 100644 --- a/examples/PowerElectronics/Microgrid/Microgrid.cpp +++ b/examples/PowerElectronics/Microgrid/Microgrid.cpp @@ -6,7 +6,7 @@ #include #include -#include "PowerElectronicsExamplesHelper/MicrogridNetwork.hpp" +#include int main(int /* argc */, char const** /* argv */) { diff --git a/examples/PowerElectronics/PowerElectronicsExamplesHelper/CMakeLists.txt b/examples/PowerElectronics/PowerElectronicsExamplesHelper/CMakeLists.txt new file mode 100644 index 000000000..7d41b162e --- /dev/null +++ b/examples/PowerElectronics/PowerElectronicsExamplesHelper/CMakeLists.txt @@ -0,0 +1,10 @@ +add_library(power_elec_microgrid_network INTERFACE) + +add_library(GridKit::power_elec_microgrid_network ALIAS power_elec_microgrid_network) + +target_link_libraries( + power_elec_microgrid_network + INTERFACE GridKit::power_elec_disgen + GridKit::power_elec_microbusdq + GridKit::power_elec_microline + GridKit::power_elec_microload) \ No newline at end of file diff --git a/examples/PowerElectronics/ScaleMicrogrid/CMakeLists.txt b/examples/PowerElectronics/ScaleMicrogrid/CMakeLists.txt index 6bee549d3..277486306 100644 --- a/examples/PowerElectronics/ScaleMicrogrid/CMakeLists.txt +++ b/examples/PowerElectronics/ScaleMicrogrid/CMakeLists.txt @@ -1,21 +1,14 @@ add_executable(scalemicrogrid ScaleMicrogrid.cpp) add_executable(scalemicrogridarbitrary ScaleMicrogridArbitrary.cpp) -target_include_directories( - scalemicrogrid - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..) - -target_include_directories( - scalemicrogridarbitrary - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..) - target_link_libraries( scalemicrogrid GridKit::power_elec_disgen GridKit::power_elec_microline GridKit::power_elec_microload GridKit::solvers_dyn - GridKit::power_elec_microbusdq) + GridKit::power_elec_microbusdq + GridKit::power_elec_microgrid_network) target_link_libraries( scalemicrogridarbitrary @@ -23,7 +16,8 @@ target_link_libraries( GridKit::power_elec_microline GridKit::power_elec_microload GridKit::solvers_dyn - GridKit::power_elec_microbusdq) + GridKit::power_elec_microbusdq + GridKit::power_elec_microgrid_network) add_test(NAME ScaleMicrogrid COMMAND $) install(TARGETS scalemicrogrid RUNTIME DESTINATION bin) diff --git a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp index a277c0e42..a0f3f0d1f 100644 --- a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp +++ b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp @@ -7,7 +7,7 @@ #include #include -#include "PowerElectronicsExamplesHelper/MicrogridNetwork.hpp" +#include using index_type = size_t; using real_type = double; diff --git a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp index dd94713f4..f0488425f 100644 --- a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp +++ b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp @@ -5,7 +5,7 @@ #include #include -#include "PowerElectronicsExamplesHelper/MicrogridNetwork.hpp" +#include using index_type = size_t; using real_type = double; From fc8fabc4ff1b7dcbd6b8e23cd07e61f822b248f2 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Wed, 26 Aug 2026 07:23:30 +0000 Subject: [PATCH 09/10] Add clone implementations for microgrid components --- .../PowerElectronics/Capacitor/Capacitor.cpp | 31 +++ .../PowerElectronics/Capacitor/Capacitor.hpp | 11 +- .../PowerElectronics/CircuitComponent.hpp | 178 +++++++++++++++++- .../DistributedGenerator.cpp | 12 ++ .../DistributedGenerator.hpp | 25 +-- .../InductionMotor/InductionMotor.cpp | 31 +++ .../InductionMotor/InductionMotor.hpp | 11 +- .../PowerElectronics/Inductor/Inductor.cpp | 12 ++ .../PowerElectronics/Inductor/Inductor.hpp | 9 +- .../LinearTransformer/LinearTransformer.cpp | 31 +++ .../LinearTransformer/LinearTransformer.hpp | 11 +- .../MicrogridBusDQ/MicrogridBusDQ.cpp | 12 ++ .../MicrogridBusDQ/MicrogridBusDQ.hpp | 9 +- .../MicrogridLine/MicrogridLine.cpp | 12 ++ .../MicrogridLine/MicrogridLine.hpp | 9 +- .../MicrogridLoad/MicrogridLoad.cpp | 12 ++ .../MicrogridLoad/MicrogridLoad.hpp | 9 +- GridKit/Model/PowerElectronics/NodeBase.hpp | 27 +++ .../PowerElectronics/Resistor/Resistor.cpp | 12 ++ .../PowerElectronics/Resistor/Resistor.hpp | 9 +- .../SynchronousMachine/SynchronousMachine.cpp | 31 +++ .../SynchronousMachine/SynchronousMachine.hpp | 11 +- .../TransmissionLine/TransmissionLine.cpp | 31 +++ .../TransmissionLine/TransmissionLine.hpp | 11 +- .../VoltageSource/VoltageSource.cpp | 12 ++ .../VoltageSource/VoltageSource.hpp | 9 +- 26 files changed, 525 insertions(+), 53 deletions(-) diff --git a/GridKit/Model/PowerElectronics/Capacitor/Capacitor.cpp b/GridKit/Model/PowerElectronics/Capacitor/Capacitor.cpp index 6c0b5fdf6..4381abc55 100644 --- a/GridKit/Model/PowerElectronics/Capacitor/Capacitor.cpp +++ b/GridKit/Model/PowerElectronics/Capacitor/Capacitor.cpp @@ -54,6 +54,25 @@ namespace GridKit return 0; } + /** + * @brief Compute the absolute tolerance for each variable in the model + * + * @param rel_tol The relative tolerance which can be used to pick the + * absolute tolerance. + * @tparam ScalarT Scalar data type + * @tparam IdxT Index data type + * @return int 0 if successful, non-zero otherwise. + * + * This represents a "noise" level close to zero for which pure relative + * error cannot be used. + */ + template + int Capacitor::setAbsoluteTolerance(RealT rel_tol) + { + abs_tol_.setToConst(static_cast(rel_tol)); + return 0; + } + /** * @brief Evaluate the resisdual of the Capcitor * @@ -119,6 +138,18 @@ namespace GridKit return 0; } + template + bool Capacitor::isCloneable() const + { + return true; + } + + template + CircuitComponent* Capacitor::clone() const + { + return new Capacitor(*this); + } + // Available template instantiations template class Capacitor; template class Capacitor; diff --git a/GridKit/Model/PowerElectronics/Capacitor/Capacitor.hpp b/GridKit/Model/PowerElectronics/Capacitor/Capacitor.hpp index d7a131a9a..0b3353c47 100644 --- a/GridKit/Model/PowerElectronics/Capacitor/Capacitor.hpp +++ b/GridKit/Model/PowerElectronics/Capacitor/Capacitor.hpp @@ -29,6 +29,7 @@ namespace GridKit using CircuitComponent::y_int_; using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; + using CircuitComponent::abs_tol_; using CircuitComponent::tag_; using CircuitComponent::f_ext_; using CircuitComponent::f_int_; @@ -50,15 +51,19 @@ namespace GridKit int initialize(); int tagDifferentiable(); + int setAbsoluteTolerance(RealT); int evaluateInternalResidual() final; int evaluateExternalResidual() final; int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT C_; diff --git a/GridKit/Model/PowerElectronics/CircuitComponent.hpp b/GridKit/Model/PowerElectronics/CircuitComponent.hpp index a033b46e7..f3a0a8d09 100644 --- a/GridKit/Model/PowerElectronics/CircuitComponent.hpp +++ b/GridKit/Model/PowerElectronics/CircuitComponent.hpp @@ -27,6 +27,138 @@ namespace GridKit CircuitComponent() = default; + CircuitComponent(const CircuitComponent& other) + : n_extern_(other.n_extern_), + n_intern_(other.n_intern_), + extern_indices_(other.extern_indices_), + size_(other.size_), + nnz_(other.nnz_), + size_quad_(other.size_quad_), + size_opt_(other.size_opt_), + current_jac_size_(other.current_jac_size_), + + // These pointers refer to storage supplied by a parent system. + // The copied component must be connected to its own storage later. + y_int_(nullptr), + yp_int_(nullptr), + f_int_(nullptr), + + tag_(other.tag_), + time_(other.time_), + alpha_(other.alpha_), + max_steps_(other.max_steps_), + idc_(other.idc_), + allocated_(other.allocated_) + { + /* + * VectorT disables its normal copy constructor and copy-assignment + * operator. Use its provided copyFromExternal() operation to perform + * an independent copy of the vector data. + */ + auto copyVector = [](VectorT& destination, const VectorT& source) + { + const IdxT source_size = source.getSize(); + + if (source_size == 0) + { + return; + } + + destination.resize(source_size); + destination.copyFromExternal(source); + }; + + /* + * Deep-copy the local-to-global connection mapping. + */ + if (other.connection_nodes_) + { + connection_nodes_ = std::make_unique(static_cast(size_)); + + for (size_t i = 0; i < static_cast(size_); ++i) + { + connection_nodes_[i] = other.connection_nodes_[i]; + } + } + + /* + * Deep-copy the COO Jacobian row indices. + */ + if (other.jacobian_coo_rows_) + { + jacobian_coo_rows_ = std::make_unique(static_cast(nnz_)); + + for (size_t i = 0; i < static_cast(nnz_); ++i) + { + jacobian_coo_rows_[i] = other.jacobian_coo_rows_[i]; + } + } + + /* + * Deep-copy the COO Jacobian column indices. + */ + if (other.jacobian_coo_cols_) + { + jacobian_coo_cols_ = std::make_unique(static_cast(nnz_)); + + for (size_t i = 0; i < static_cast(nnz_); ++i) + { + jacobian_coo_cols_[i] = other.jacobian_coo_cols_[i]; + } + } + + /* + * Deep-copy the COO Jacobian values. + */ + if (other.jacobian_coo_values_) + { + jacobian_coo_values_ = std::make_unique(static_cast(nnz_)); + + for (size_t i = 0; i < static_cast(nnz_); ++i) + { + jacobian_coo_values_[i] = other.jacobian_coo_values_[i]; + } + } + + if (size_ > 0) + { + y_ext_ = std::make_unique(static_cast(size_)); + yp_ext_ = std::make_unique(static_cast(size_)); + f_ext_ = std::make_unique(static_cast(size_)); + + for (size_t i = 0; i < static_cast(size_); ++i) + { + y_ext_[i] = nullptr; + yp_ext_[i] = nullptr; + f_ext_[i] = nullptr; + } + } + + // State, state derivative, residual, and absolute tolerance. + copyVector(y_, other.y_); + copyVector(yp_, other.yp_); + copyVector(f_, other.f_); + copyVector(abs_tol_, other.abs_tol_); + copyVector(g_, other.g_); + copyVector(yB_, other.yB_); + copyVector(ypB_, other.ypB_); + copyVector(fB_, other.fB_); + copyVector(gB_, other.gB_); + copyVector(param_, other.param_); + copyVector(param_up_, other.param_up_); + copyVector(param_lo_, other.param_lo_); + } + + virtual CircuitComponent* clone() const + { + return nullptr; + } + + virtual bool isCloneable() const + { + return false; + } + /** * @note Cannot be marked final, since it is overriden to recurse in the system model. */ @@ -51,7 +183,7 @@ namespace GridKit return this->n_intern_; } - std::set getExternIndices() + std::set getExternIndices() { return this->extern_indices_; } @@ -69,7 +201,7 @@ namespace GridKit int setInternalConnectionNodes(size_t local_index, IdxT global_index) { assert(!extern_indices_.contains(static_cast(local_index))); - connection_nodes_[local_index] = global_index; + setConnectionNodes(local_index, global_index); return 0; } @@ -88,10 +220,27 @@ namespace GridKit int setExternalConnectionNodes(size_t local_index, ExternalConnection connection) { assert(extern_indices_.contains(local_index)); - y_ext_[local_index] = connection.y_; - yp_ext_[local_index] = connection.yp_; - f_ext_[local_index] = connection.f_; - connection_nodes_[local_index] = connection.idx_; + y_ext_[local_index] = connection.y_; + yp_ext_[local_index] = connection.yp_; + f_ext_[local_index] = connection.f_; + setConnectionNodes(local_index, connection.idx_); + return 0; + } + + /** + * @brief Update the connection index for a variable. + * + * Sets only the connection index without modifying the variable's + * internal/external classification or its associated data pointers. + * + * @param local_index Index of the local variable. + * @param connection_index New connection index for the variable. + * + * @return int 0 if successful. + */ + int setConnectionNodes(size_t local_index, IdxT connection_index) + { + connection_nodes_[local_index] = connection_index; return 0; } @@ -132,9 +281,10 @@ namespace GridKit jacobian_coo_cols_ = std::make_unique(static_cast(nnz_)); jacobian_coo_values_ = std::make_unique(static_cast(nnz_)); - y_ext_ = std::make_unique(static_cast(size_)); - yp_ext_ = std::make_unique(static_cast(size_)); - f_ext_ = std::make_unique(static_cast(size_)); + y_ext_ = std::make_unique(static_cast(size_)); + yp_ext_ = std::make_unique(static_cast(size_)); + f_ext_ = std::make_unique(static_cast(size_)); + connection_nodes_ = std::make_unique(static_cast(size_)); tag_.resize(static_cast(size_)); @@ -441,6 +591,16 @@ namespace GridKit return idc_; } + /** + * @brief Check whether the component has already been allocated. + * + * @return true if allocate() has previously completed, false otherwise. + */ + bool isAllocated() const + { + return allocated_; + } + protected: /** * @brief Allocate state and residual storage owned by this component. diff --git a/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.cpp b/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.cpp index aa538933f..1cc86e989 100644 --- a/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.cpp +++ b/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.cpp @@ -422,6 +422,18 @@ namespace GridKit return 0; } + template + bool DistributedGenerator::isCloneable() const + { + return true; + } + + template + CircuitComponent* DistributedGenerator::clone() const + { + return new DistributedGenerator(*this); + } + // Available template instantiations template class DistributedGenerator; template class DistributedGenerator; diff --git a/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.hpp b/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.hpp index ab7e340f1..8a5219848 100644 --- a/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.hpp +++ b/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.hpp @@ -75,18 +75,21 @@ namespace GridKit NodeT* node_bus); virtual ~DistributedGenerator(); - int initialize(); - int allocate() final; - int tagDifferentiable(); - int setAbsoluteTolerance(RealT); - int evaluateInternalResidual() final; - int evaluateExternalResidual() final; - int evaluateJacobian(); - int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initialize(); + int allocate() final; + int tagDifferentiable(); + int setAbsoluteTolerance(RealT); + int evaluateInternalResidual() final; + int evaluateExternalResidual() final; + int evaluateJacobian(); + int evaluateIntegrand(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT wb_; diff --git a/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.cpp b/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.cpp index 74aabb549..d15913e72 100644 --- a/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.cpp +++ b/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.cpp @@ -65,6 +65,25 @@ namespace GridKit return 0; } + /** + * @brief Compute the absolute tolerance for each variable in the model + * + * @param rel_tol The relative tolerance which can be used to pick the + * absolute tolerance. + * @tparam ScalarT Scalar data type + * @tparam IdxT Index data type + * @return int 0 if successful, non-zero otherwise. + * + * This represents a "noise" level close to zero for which pure relative + * error cannot be used. + */ + template + int InductionMotor::setAbsoluteTolerance(RealT rel_tol) + { + abs_tol_.setToConst(static_cast(rel_tol)); + return 0; + } + /** * @brief Contributes to the resisdual * @@ -131,6 +150,18 @@ namespace GridKit return 0; } + template + bool InductionMotor::isCloneable() const + { + return true; + } + + template + CircuitComponent* InductionMotor::clone() const + { + return new InductionMotor(*this); + } + // Available template instantiations template class InductionMotor; template class InductionMotor; diff --git a/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.hpp b/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.hpp index 122cd4d30..6f1724670 100644 --- a/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.hpp +++ b/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.hpp @@ -29,6 +29,7 @@ namespace GridKit using CircuitComponent::y_int_; using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; + using CircuitComponent::abs_tol_; using CircuitComponent::tag_; using CircuitComponent::f_ext_; using CircuitComponent::f_int_; @@ -50,15 +51,19 @@ namespace GridKit int initialize(); int tagDifferentiable(); + int setAbsoluteTolerance(RealT); int evaluateInternalResidual() final; int evaluateExternalResidual() final; int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT Lls_; diff --git a/GridKit/Model/PowerElectronics/Inductor/Inductor.cpp b/GridKit/Model/PowerElectronics/Inductor/Inductor.cpp index 0e6e7ea28..6e9969366 100644 --- a/GridKit/Model/PowerElectronics/Inductor/Inductor.cpp +++ b/GridKit/Model/PowerElectronics/Inductor/Inductor.cpp @@ -149,6 +149,18 @@ namespace GridKit return 0; } + template + bool Inductor::isCloneable() const + { + return true; + } + + template + CircuitComponent* Inductor::clone() const + { + return new Inductor(*this); + } + // Available template instantiations template class Inductor; template class Inductor; diff --git a/GridKit/Model/PowerElectronics/Inductor/Inductor.hpp b/GridKit/Model/PowerElectronics/Inductor/Inductor.hpp index b82ce1070..30d25db79 100644 --- a/GridKit/Model/PowerElectronics/Inductor/Inductor.hpp +++ b/GridKit/Model/PowerElectronics/Inductor/Inductor.hpp @@ -60,10 +60,13 @@ namespace GridKit int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT L_; diff --git a/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.cpp b/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.cpp index 455ef202f..864250abc 100644 --- a/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.cpp +++ b/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.cpp @@ -67,6 +67,25 @@ namespace GridKit return 0; } + /** + * @brief Compute the absolute tolerance for each variable in the model + * + * @param rel_tol The relative tolerance which can be used to pick the + * absolute tolerance. + * @tparam ScalarT Scalar data type + * @tparam IdxT Index data type + * @return int 0 if successful, non-zero otherwise. + * + * This represents a "noise" level close to zero for which pure relative + * error cannot be used. + */ + template + int LinearTransformer::setAbsoluteTolerance(RealT rel_tol) + { + abs_tol_.setToConst(static_cast(rel_tol)); + return 0; + } + /** * @brief Computes the component resisdual */ @@ -116,6 +135,18 @@ namespace GridKit return 0; } + template + bool LinearTransformer::isCloneable() const + { + return true; + } + + template + CircuitComponent* LinearTransformer::clone() const + { + return new LinearTransformer(*this); + } + // Available template instantiations template class LinearTransformer; template class LinearTransformer; diff --git a/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.hpp b/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.hpp index 62dc84305..6b75dcc1d 100644 --- a/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.hpp +++ b/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.hpp @@ -29,6 +29,7 @@ namespace GridKit using CircuitComponent::y_int_; using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; + using CircuitComponent::abs_tol_; using CircuitComponent::tag_; using CircuitComponent::f_ext_; using CircuitComponent::f_int_; @@ -50,15 +51,19 @@ namespace GridKit int initialize(); int tagDifferentiable(); + int setAbsoluteTolerance(RealT); int evaluateInternalResidual() final; int evaluateExternalResidual() final; int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT L0_; diff --git a/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.cpp b/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.cpp index 462c200f8..1fee11c4b 100644 --- a/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.cpp +++ b/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.cpp @@ -152,6 +152,18 @@ namespace GridKit return 0; } + template + bool MicrogridBusDQ::isCloneable() const + { + return true; + } + + template + CircuitComponent* MicrogridBusDQ::clone() const + { + return new MicrogridBusDQ(*this); + } + // Available template instantiations template class MicrogridBusDQ; template class MicrogridBusDQ; diff --git a/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.hpp b/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.hpp index 111ca7be8..2314700a3 100644 --- a/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.hpp +++ b/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.hpp @@ -60,10 +60,13 @@ namespace GridKit int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT RN_; diff --git a/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.cpp b/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.cpp index efa5c2a36..7e5f993c4 100644 --- a/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.cpp +++ b/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.cpp @@ -184,6 +184,18 @@ namespace GridKit return 0; } + template + bool MicrogridLine::isCloneable() const + { + return true; + } + + template + CircuitComponent* MicrogridLine::clone() const + { + return new MicrogridLine(*this); + } + // Available template instantiations template class MicrogridLine; template class MicrogridLine; diff --git a/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.hpp b/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.hpp index 1354a9d9b..041562cbb 100644 --- a/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.hpp +++ b/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.hpp @@ -60,10 +60,13 @@ namespace GridKit int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT R_; diff --git a/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.cpp b/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.cpp index 36ac6c375..9e6098d0f 100644 --- a/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.cpp +++ b/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.cpp @@ -175,6 +175,18 @@ namespace GridKit return 0; } + template + bool MicrogridLoad::isCloneable() const + { + return true; + } + + template + CircuitComponent* MicrogridLoad::clone() const + { + return new MicrogridLoad(*this); + } + // Available template instantiations template class MicrogridLoad; template class MicrogridLoad; diff --git a/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.hpp b/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.hpp index 931983d50..6189e941c 100644 --- a/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.hpp +++ b/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.hpp @@ -60,10 +60,13 @@ namespace GridKit int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT R_; diff --git a/GridKit/Model/PowerElectronics/NodeBase.hpp b/GridKit/Model/PowerElectronics/NodeBase.hpp index 077854b97..b39539781 100644 --- a/GridKit/Model/PowerElectronics/NodeBase.hpp +++ b/GridKit/Model/PowerElectronics/NodeBase.hpp @@ -136,6 +136,23 @@ namespace GridKit }; } + /** + * @brief Update the connection index for a variable. + * + * Changes only the connection index without modifying the variable's + * internal/external classification or its associated data pointers. + * + * @param local_index Index of the local variable. + * @param connection_index New connection index for the variable. + * + * @return int 0 if successful. + */ + int setConnectionNodes(size_t local_index, IdxT connection_index) + { + connection_nodes_[local_index] = connection_index; + return 0; + } + int allocate() override { size_t size = static_cast(n_intern_ + n_extern_); @@ -392,6 +409,16 @@ namespace GridKit return gB_; } + /** + * @brief Check whether the Node has already been allocated. + * + * @return true if allocate() has previously completed, false otherwise. + */ + bool isAllocated() const + { + return allocated_; + } + private: void allocateVectors(IdxT n) { diff --git a/GridKit/Model/PowerElectronics/Resistor/Resistor.cpp b/GridKit/Model/PowerElectronics/Resistor/Resistor.cpp index 8fba09a55..55caa4837 100644 --- a/GridKit/Model/PowerElectronics/Resistor/Resistor.cpp +++ b/GridKit/Model/PowerElectronics/Resistor/Resistor.cpp @@ -139,6 +139,18 @@ namespace GridKit return 0; } + template + bool Resistor::isCloneable() const + { + return true; + } + + template + CircuitComponent* Resistor::clone() const + { + return new Resistor(*this); + } + // Available template instantiations template class Resistor; template class Resistor; diff --git a/GridKit/Model/PowerElectronics/Resistor/Resistor.hpp b/GridKit/Model/PowerElectronics/Resistor/Resistor.hpp index 540ab4d20..19c90a190 100644 --- a/GridKit/Model/PowerElectronics/Resistor/Resistor.hpp +++ b/GridKit/Model/PowerElectronics/Resistor/Resistor.hpp @@ -60,10 +60,13 @@ namespace GridKit int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT R_; diff --git a/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.cpp b/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.cpp index 5ec5b3b91..408bf241c 100644 --- a/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.cpp +++ b/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.cpp @@ -82,6 +82,25 @@ namespace GridKit return 0; } + /** + * @brief Compute the absolute tolerance for each variable in the model + * + * @param rel_tol The relative tolerance which can be used to pick the + * absolute tolerance. + * @tparam ScalarT Scalar data type + * @tparam IdxT Index data type + * @return int 0 if successful, non-zero otherwise. + * + * This represents a "noise" level close to zero for which pure relative + * error cannot be used. + */ + template + int SynchronousMachine::setAbsoluteTolerance(RealT rel_tol) + { + abs_tol_.setToConst(static_cast(rel_tol)); + return 0; + } + /** * @brief Compute the resisdual of the component. * @@ -165,6 +184,18 @@ namespace GridKit return 0; } + template + bool SynchronousMachine::isCloneable() const + { + return true; + } + + template + CircuitComponent* SynchronousMachine::clone() const + { + return new SynchronousMachine(*this); + } + // Available template instantiations template class SynchronousMachine; template class SynchronousMachine; diff --git a/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.hpp b/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.hpp index 80b68eed2..7cf040583 100644 --- a/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.hpp +++ b/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.hpp @@ -31,6 +31,7 @@ namespace GridKit using CircuitComponent::y_int_; using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; + using CircuitComponent::abs_tol_; using CircuitComponent::tag_; using CircuitComponent::f_ext_; using CircuitComponent::f_int_; @@ -52,15 +53,19 @@ namespace GridKit int initialize(); int tagDifferentiable(); + int setAbsoluteTolerance(RealT); int evaluateInternalResidual() final; int evaluateExternalResidual() final; int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT Lls_; diff --git a/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.cpp b/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.cpp index f4700e275..cfefa499f 100644 --- a/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.cpp +++ b/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.cpp @@ -65,6 +65,25 @@ namespace GridKit return 0; } + /** + * @brief Compute the absolute tolerance for each variable in the model + * + * @param rel_tol The relative tolerance which can be used to pick the + * absolute tolerance. + * @tparam ScalarT Scalar data type + * @tparam IdxT Index data type + * @return int 0 if successful, non-zero otherwise. + * + * This represents a "noise" level close to zero for which pure relative + * error cannot be used. + */ + template + int TransmissionLine::setAbsoluteTolerance(RealT rel_tol) + { + abs_tol_.setToConst(static_cast(rel_tol)); + return 0; + } + /** * @brief Evaluate residual of transmission line * @@ -186,6 +205,18 @@ namespace GridKit return 0; } + template + bool TransmissionLine::isCloneable() const + { + return true; + } + + template + CircuitComponent* TransmissionLine::clone() const + { + return new TransmissionLine(*this); + } + // Available template instantiations template class TransmissionLine; template class TransmissionLine; diff --git a/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.hpp b/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.hpp index 091984c89..c9743e9dd 100644 --- a/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.hpp +++ b/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.hpp @@ -33,6 +33,7 @@ namespace GridKit using CircuitComponent::y_int_; using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; + using CircuitComponent::abs_tol_; using CircuitComponent::tag_; using CircuitComponent::f_ext_; using CircuitComponent::f_int_; @@ -54,15 +55,19 @@ namespace GridKit int initialize(); int tagDifferentiable(); + int setAbsoluteTolerance(RealT); int evaluateInternalResidual() final; int evaluateExternalResidual() final; int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT R_; diff --git a/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.cpp b/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.cpp index 52f021a5a..3ac673129 100644 --- a/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.cpp +++ b/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.cpp @@ -142,6 +142,18 @@ namespace GridKit return 0; } + template + bool VoltageSource::isCloneable() const + { + return true; + } + + template + CircuitComponent* VoltageSource::clone() const + { + return new VoltageSource(*this); + } + // Available template instantiations template class VoltageSource; template class VoltageSource; diff --git a/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.hpp b/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.hpp index 814fa5ec5..ab9125f40 100644 --- a/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.hpp +++ b/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.hpp @@ -60,10 +60,13 @@ namespace GridKit int evaluateJacobian() final; int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT V_; From 1802d2f8006bccffbc7c48fe0417ee2953a7a485 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Wed, 26 Aug 2026 07:24:45 +0000 Subject: [PATCH 10/10] Add tests for component cloning --- .../UnitTests/PowerElectronics/CMakeLists.txt | 11 + .../PowerElectronics/ComponentCloneTests.hpp | 263 ++++++++++++++++++ .../runComponentCloneTests.cpp | 15 + 3 files changed, 289 insertions(+) create mode 100644 tests/UnitTests/PowerElectronics/ComponentCloneTests.hpp create mode 100644 tests/UnitTests/PowerElectronics/runComponentCloneTests.cpp diff --git a/tests/UnitTests/PowerElectronics/CMakeLists.txt b/tests/UnitTests/PowerElectronics/CMakeLists.txt index 74d50eb1e..55a0ff790 100644 --- a/tests/UnitTests/PowerElectronics/CMakeLists.txt +++ b/tests/UnitTests/PowerElectronics/CMakeLists.txt @@ -3,6 +3,17 @@ target_link_libraries( test_power_electronics_node PRIVATE GridKit::power_electronics_circuit_node GridKit::testing) +add_executable(test_power_electronics_component_clone runComponentCloneTests.cpp) +target_link_libraries( + test_power_electronics_component_clone + PRIVATE GridKit::power_elec_disgen + GridKit::power_elec_microline + GridKit::power_elec_microload + GridKit::power_elec_microbusdq + GridKit::testing) + add_test(NAME PowerElectronicsNodeTest COMMAND $) +add_test(NAME PowerElectronicsComponentCloneTest COMMAND $) install(TARGETS test_power_electronics_node RUNTIME DESTINATION bin) +install(TARGETS test_power_electronics_component_clone RUNTIME DESTINATION bin) diff --git a/tests/UnitTests/PowerElectronics/ComponentCloneTests.hpp b/tests/UnitTests/PowerElectronics/ComponentCloneTests.hpp new file mode 100644 index 000000000..5124442d8 --- /dev/null +++ b/tests/UnitTests/PowerElectronics/ComponentCloneTests.hpp @@ -0,0 +1,263 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace GridKit +{ + template + bool verifyComponentClone(ComponentT& component) + { + using RealT = typename CircuitComponent::RealT; + + bool success = true; + + auto* clone = dynamic_cast(component.clone()); + + if (clone == nullptr) + { + return false; + } + + /************************************************************************** + * Verify the Clone Initially Matches the Original + **************************************************************************/ + + success &= clone != &component; + success &= clone->size() == component.size(); + success &= clone->nnz() == component.nnz(); + success &= clone->getInternalSize() == component.getInternalSize(); + success &= clone->getExternSize() == component.getExternSize(); + success &= clone->getExternIndices() == component.getExternIndices(); + success &= clone->getIDcomponent() == component.getIDcomponent(); + + /************************************************************************** + * Verify Connection Independence + **************************************************************************/ + + for (IdxT i = 0; i < component.size(); ++i) + { + const IdxT connection = component.getNodeConnection(i); + + success &= clone->getNodeConnection(i) == connection; + + clone->setConnectionNodes(i, connection + 1); + + success &= component.getNodeConnection(i) == connection; + success &= clone->getNodeConnection(i) == connection + 1; + + clone->setConnectionNodes(i, connection); + } + + /************************************************************************** + * Verify State Independence + **************************************************************************/ + + auto checkVectorIndependence = [&success](auto& original, auto& copy) + { + success &= original.getSize() == copy.getSize(); + + if (original.getSize() == 0) + { + return; + } + + auto* original_data = original.getData(); + auto* copy_data = copy.getData(); + + success &= original_data != copy_data; + + const auto original_value = original_data[0]; + + copy_data[0] = original_value + 1.0; + + success &= original_data[0] == original_value; + success &= copy_data[0] == original_value + 1.0; + + copy_data[0] = original_value; + }; + + checkVectorIndependence(component.y(), clone->y()); + checkVectorIndependence(component.yp(), clone->yp()); + checkVectorIndependence(component.getResidual(), clone->getResidual()); + checkVectorIndependence(component.absoluteTolerance(), clone->absoluteTolerance()); + checkVectorIndependence(component.param(), clone->param()); + + /************************************************************************** + * Verify Jacobian Independence + **************************************************************************/ + + if (component.nnz() > 0) + { + auto* original_rows = component.jacobianCooRows(); + auto* original_cols = component.jacobianCooCols(); + auto* original_values = component.jacobianCooValues(); + + auto* clone_rows = clone->jacobianCooRows(); + auto* clone_cols = clone->jacobianCooCols(); + auto* clone_values = clone->jacobianCooValues(); + + success &= clone_rows != original_rows; + success &= clone_cols != original_cols; + success &= clone_values != original_values; + + for (IdxT i = 0; i < component.nnz(); ++i) + { + success &= clone_rows[i] == original_rows[i]; + success &= clone_cols[i] == original_cols[i]; + success &= clone_values[i] == original_values[i]; + } + + const IdxT original_row = original_rows[0]; + const IdxT original_col = original_cols[0]; + const RealT original_value = original_values[0]; + + clone_rows[0] = original_row + 1; + clone_cols[0] = original_col + 1; + clone_values[0] = original_value + 1.0; + + success &= original_rows[0] == original_row; + success &= original_cols[0] == original_col; + success &= original_values[0] == original_value; + + clone_rows[0] = original_row; + clone_cols[0] = original_col; + clone_values[0] = original_value; + } + + delete clone; + + return success; + } + + namespace Testing + { + template + class CircuitComponentCloneTests + { + using SignalNode = PowerElectronics::SignalNode; + using Bus = PowerElectronics::MicrogridBus; + using BusDQ = MicrogridBusDQ; + using Generator = DistributedGenerator; + using GeneratorParameters = DistributedGeneratorParameters; + using Line = MicrogridLine; + using Load = MicrogridLoad; + + public: + CircuitComponentCloneTests() + { + /************************************************************************** + * Construct Network Nodes + **************************************************************************/ + + signal_.allocate(); + + bus1_.allocate(); + bus2_.allocate(); + + /************************************************************************** + * Distributed Generator Parameters + **************************************************************************/ + + generator_parameters_.wb_ = 2.0 * M_PI * 50.0; + generator_parameters_.wc_ = 31.41; + generator_parameters_.mp_ = 9.4e-5; + generator_parameters_.Vn_ = 380.0; + generator_parameters_.nq_ = 1.3e-3; + generator_parameters_.F_ = 0.75; + generator_parameters_.Kiv_ = 420.0; + generator_parameters_.Kpv_ = 0.1; + generator_parameters_.Kic_ = 2.0e4; + generator_parameters_.Kpc_ = 15.0; + generator_parameters_.Cf_ = 5.0e-5; + generator_parameters_.rLf_ = 0.1; + generator_parameters_.Lf_ = 1.35e-3; + generator_parameters_.rLc_ = 0.03; + generator_parameters_.Lc_ = 0.35e-3; + + /************************************************************************** + * Construct Components + **************************************************************************/ + + generator_ = new Generator(1, generator_parameters_, true, &signal_, &bus1_); + + line_ = new Line(2, 0.23, 0.1 / (2.0 * M_PI * 50.0), &signal_, &bus1_, &bus2_); + + load_ = new Load(3, 3.0, 2.0 / (2.0 * M_PI * 50.0), &signal_, &bus1_); + + bus_dq_ = new BusDQ(4, 1.0e4, &bus1_); + + /************************************************************************** + * Allocate Components + **************************************************************************/ + + generator_->allocate(); + line_->allocate(); + load_->allocate(); + bus_dq_->allocate(); + } + + ~CircuitComponentCloneTests() + { + delete generator_; + delete line_; + delete load_; + delete bus_dq_; + } + + TestOutcome distributedGeneratorClone() + { + TestStatus success = true; + + success *= verifyComponentClone(*generator_); + + return success.report(__func__); + } + + TestOutcome microgridLineClone() + { + TestStatus success = true; + + success *= verifyComponentClone(*line_); + + return success.report(__func__); + } + + TestOutcome microgridLoadClone() + { + TestStatus success = true; + + success *= verifyComponentClone(*load_); + + return success.report(__func__); + } + + TestOutcome microgridBusDQClone() + { + TestStatus success = true; + + success *= verifyComponentClone(*bus_dq_); + + return success.report(__func__); + } + + private: + SignalNode signal_; + + Bus bus1_; + Bus bus2_; + + GeneratorParameters generator_parameters_; + + Generator* generator_{nullptr}; + Line* line_{nullptr}; + Load* load_{nullptr}; + BusDQ* bus_dq_{nullptr}; + }; + } // namespace Testing +} // namespace GridKit diff --git a/tests/UnitTests/PowerElectronics/runComponentCloneTests.cpp b/tests/UnitTests/PowerElectronics/runComponentCloneTests.cpp new file mode 100644 index 000000000..dfb5fa97f --- /dev/null +++ b/tests/UnitTests/PowerElectronics/runComponentCloneTests.cpp @@ -0,0 +1,15 @@ +#include "ComponentCloneTests.hpp" + +int main() +{ + GridKit::Testing::CircuitComponentCloneTests tests; + + GridKit::Testing::TestingResults result; + + result += tests.distributedGeneratorClone(); + result += tests.microgridLineClone(); + result += tests.microgridLoadClone(); + result += tests.microgridBusDQClone(); + + return result.summary(); +}