From cfa3c43f8bbc0771c23f895e2715db96e9742cd1 Mon Sep 17 00:00:00 2001 From: Alexander Novotny Date: Mon, 27 Apr 2026 15:03:29 -0400 Subject: [PATCH 01/13] Remove external variable copy --- .../PowerElectronics/Bus/GroundedBus.hpp | 21 +-- .../PowerElectronics/Capacitor/Capacitor.cpp | 11 +- .../PowerElectronics/Capacitor/Capacitor.hpp | 6 +- .../PowerElectronics/CircuitComponent.hpp | 91 +++++++++-- .../DistributedGenerator.cpp | 32 ++-- .../DistributedGenerator.hpp | 6 +- .../InductionMotor/InductionMotor.cpp | 27 ++-- .../InductionMotor/InductionMotor.hpp | 6 +- .../PowerElectronics/Inductor/Inductor.cpp | 11 +- .../PowerElectronics/Inductor/Inductor.hpp | 6 +- .../LinearTransformer/LinearTransformer.cpp | 13 +- .../LinearTransformer/LinearTransformer.hpp | 6 +- .../MicrogridBusDQ/MicrogridBusDQ.cpp | 9 +- .../MicrogridBusDQ/MicrogridBusDQ.hpp | 6 +- .../MicrogridLine/MicrogridLine.cpp | 25 ++- .../MicrogridLine/MicrogridLine.hpp | 6 +- .../MicrogridLoad/MicrogridLoad.cpp | 21 +-- .../MicrogridLoad/MicrogridLoad.hpp | 6 +- GridKit/Model/PowerElectronics/NodeBase.hpp | 51 ++++-- .../PowerElectronics/Resistor/Resistor.cpp | 8 +- .../PowerElectronics/Resistor/Resistor.hpp | 6 +- .../SynchronousMachine/SynchronousMachine.cpp | 23 +-- .../SynchronousMachine/SynchronousMachine.hpp | 6 +- .../SystemModelPowerElectronics.hpp | 148 ++++++------------ .../TransmissionLine/TransmissionLine.cpp | 30 ++-- .../TransmissionLine/TransmissionLine.hpp | 6 +- .../VoltageSource/VoltageSource.cpp | 12 +- .../VoltageSource/VoltageSource.hpp | 6 +- .../DistributedGeneratorTest/DGTest.cpp | 24 +-- .../PowerElectronics/Microgrid/Microgrid.cpp | 2 +- .../PowerElectronics/RLCircuit/RLCircuit.cpp | 4 - .../ScaleMicrogrid/ScaleMicrogrid.cpp | 2 +- .../ScaleMicrogridArbitrary.cpp | 2 +- 33 files changed, 292 insertions(+), 347 deletions(-) diff --git a/GridKit/Model/PowerElectronics/Bus/GroundedBus.hpp b/GridKit/Model/PowerElectronics/Bus/GroundedBus.hpp index 88fc0d625..b6a4fe25c 100644 --- a/GridKit/Model/PowerElectronics/Bus/GroundedBus.hpp +++ b/GridKit/Model/PowerElectronics/Bus/GroundedBus.hpp @@ -9,7 +9,11 @@ namespace GridKit template class GroundedBus : public NodeBase { - using NodeBase::y; + using ExternalConnection = typename CircuitComponent::ExternalConnection; + + using NodeBase::y_ext_; + using NodeBase::yp_ext_; + using NodeBase::f_ext_; public: GroundedBus(ScalarT voltage) @@ -17,30 +21,19 @@ namespace GridKit { } - int initialize() final - { - if (int err_code = NodeBase::initialize()) - return err_code; - - auto* y_data = y().getData(); - y_data[0] = voltage_; - y().setDataUpdated(); - - return 0; - } - int allocate() final { if (int err_code = NodeBase::allocate()) return err_code; - this->setExternalConnectionNodes(0, INVALID_INDEX); + this->setExternalConnectionNodes(0, ExternalConnection{.y_ = &voltage_, .yp_ = &dummy_, .f_ = &dummy_, .idx_ = INVALID_INDEX}); return 0; } private: ScalarT voltage_; + ScalarT dummy_; }; } // namespace PowerElectronics } // namespace GridKit diff --git a/GridKit/Model/PowerElectronics/Capacitor/Capacitor.cpp b/GridKit/Model/PowerElectronics/Capacitor/Capacitor.cpp index 2c2ad2ae0..aab348679 100644 --- a/GridKit/Model/PowerElectronics/Capacitor/Capacitor.cpp +++ b/GridKit/Model/PowerElectronics/Capacitor/Capacitor.cpp @@ -59,22 +59,17 @@ namespace GridKit template int Capacitor::evaluateInternalResidual() { - const auto* y = y_.getData(); - - f_int_[0] = -C_ * yp_int_[0] + y[0] - y[1] - y_int_[0]; + f_int_[0] = -C_ * yp_int_[0] + *y_ext_[0] - *y_ext_[1] - y_int_[0]; return 0; } template int Capacitor::evaluateExternalResidual() { - auto* f = f_.getData(); - // input - f[0] = C_ * yp_int_[0]; + *f_ext_[0] += C_ * yp_int_[0]; // output - f[1] = -C_ * yp_int_[0]; - f_.setDataUpdated(); + *f_ext_[1] += -C_ * yp_int_[0]; return 0; } diff --git a/GridKit/Model/PowerElectronics/Capacitor/Capacitor.hpp b/GridKit/Model/PowerElectronics/Capacitor/Capacitor.hpp index a45b55535..d7a131a9a 100644 --- a/GridKit/Model/PowerElectronics/Capacitor/Capacitor.hpp +++ b/GridKit/Model/PowerElectronics/Capacitor/Capacitor.hpp @@ -25,12 +25,12 @@ namespace GridKit using CircuitComponent::nnz_; using CircuitComponent::time_; using CircuitComponent::alpha_; - using CircuitComponent::y_; + using CircuitComponent::y_ext_; using CircuitComponent::y_int_; - using CircuitComponent::yp_; + using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; using CircuitComponent::tag_; - using CircuitComponent::f_; + using CircuitComponent::f_ext_; using CircuitComponent::f_int_; using CircuitComponent::g_; using CircuitComponent::yB_; diff --git a/GridKit/Model/PowerElectronics/CircuitComponent.hpp b/GridKit/Model/PowerElectronics/CircuitComponent.hpp index 026db4df8..f37b715ce 100644 --- a/GridKit/Model/PowerElectronics/CircuitComponent.hpp +++ b/GridKit/Model/PowerElectronics/CircuitComponent.hpp @@ -55,6 +55,28 @@ namespace GridKit return this->extern_indices_; } + struct ExternalConnection + { + const ScalarT* y_; + const ScalarT* yp_; + ScalarT* f_; + IdxT idx_; + }; + + /** + * @brief Create the mappings from local to global indices + * + * @param local_index + * @param global_index + * @return int + */ + int setInternalConnectionNodes(size_t local_index, size_t global_index) + { + assert(!extern_indices_.contains(local_index)); + connection_nodes_[local_index] = global_index; + return 0; + } + /** * @brief Create the mappings from local to global indices * @@ -62,9 +84,13 @@ namespace GridKit * @param global_index * @return int */ - int setExternalConnectionNodes(IdxT local_index, IdxT global_index) + int setExternalConnectionNodes(size_t local_index, ExternalConnection global_index) { - connection_nodes_[static_cast(local_index)] = global_index; + assert(extern_indices_.contains(local_index)); + y_ext_[local_index] = global_index.y_; + yp_ext_[local_index] = global_index.yp_; + f_ext_[local_index] = global_index.f_; + connection_nodes_[local_index] = global_index.idx_; return 0; } @@ -74,11 +100,24 @@ namespace GridKit * f(local_index) = global_index * * @param local_index index of local value in vector - * @return IdxT Index of the same value in the global vector + * @return size_t Index of the same value in the global vector */ - IdxT getNodeConnection(IdxT local_index) const + ExternalConnection getNodeConnection(size_t local_index) const { - return connection_nodes_[local_index]; + return ExternalConnection{ + .y_ = y_ext_[local_index], + .yp_ = yp_ext_[local_index], + .f_ = f_ext_[local_index], + .idx_ = connection_nodes_[local_index], + }; + } + + int initialize() override + { + y_.setDataUpdated(); + yp_.setDataUpdated(); + + return 0; } /** @@ -97,7 +136,10 @@ namespace GridKit jacobian_coo_cols_ = std::make_unique(static_cast(nnz_)); jacobian_coo_values_ = std::make_unique(static_cast(nnz_)); - connection_nodes_ = 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_)); if (!allocated_) { @@ -151,6 +193,8 @@ namespace GridKit if (int err_code = evaluateInternalResidual()) return err_code; + f_.setDataUpdated(); + return evaluateExternalResidual(); } @@ -403,19 +447,27 @@ namespace GridKit /** * @brief Allocate state and residual storage owned by this component. */ - void allocateVectors(IdxT n) + void allocateVectors(IdxT n, bool system = false) { - y_.resize(n); - yp_.resize(n); - f_.resize(n); abs_tol_.resize(n); + + if (system) + { + y_.resize(n); + yp_.resize(n); + f_.resize(n); + + y_int_ = y_.getData(); + yp_int_ = yp_.getData(); + f_int_ = f_.getData(); + } } - size_t n_extern_; - size_t n_intern_; - std::set extern_indices_; + size_t n_extern_; + size_t n_intern_; + std::set extern_indices_; ///@todo may want to replace the mapping of connection_nodes to Node objects instead of IdxT. Allows for container free setup - std::unique_ptr connection_nodes_; + std::unique_ptr connection_nodes_; protected: IdxT size_{0}; @@ -438,11 +490,16 @@ namespace GridKit /// @brief A pointer to the internal residuals of this component ScalarT* f_int_; - VectorT y_; - VectorT yp_; + std::unique_ptr y_ext_; + std::unique_ptr yp_ext_; + std::unique_ptr f_ext_; + + VectorT y_; + VectorT yp_; + VectorT f_; + std::vector tag_; VectorT abs_tol_; - VectorT f_; VectorT g_; diff --git a/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.cpp b/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.cpp index 7f858f7d2..0a7f7c373 100644 --- a/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.cpp +++ b/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.cpp @@ -103,13 +103,12 @@ namespace GridKit template int DistributedGenerator::evaluateInternalResidual() { - ScalarT omega = wb_ - mp_ * y_int_[0]; - ScalarT delta = refframe_ ? ScalarT(0.0) : y_int_[12]; - const auto* y = y_.getData(); + ScalarT omega = wb_ - mp_ * y_int_[0]; + ScalarT delta = refframe_ ? ScalarT(0.0) : y_int_[12]; // Take incoming voltages to current rotator reference frame - ScalarT vbd_in = std::cos(delta) * y[1] + std::sin(delta) * y[2]; - ScalarT vbq_in = -std::sin(delta) * y[1] + std::cos(delta) * y[2]; + ScalarT vbd_in = std::cos(delta) * *y_ext_[1] + std::sin(delta) * *y_ext_[2]; + ScalarT vbq_in = -std::sin(delta) * *y_ext_[1] + std::cos(delta) * *y_ext_[2]; // ### Internal Componenets ## // P and Q equations @@ -146,7 +145,7 @@ namespace GridKit // Rotor difference angle if (!refframe_) - f_int_[12] = -yp_int_[12] + omega - y[0]; + f_int_[12] = -yp_int_[12] + omega - *y_ext_[0]; return 0; } @@ -154,26 +153,23 @@ namespace GridKit template int DistributedGenerator::evaluateExternalResidual() { - ScalarT omega = wb_ - mp_ * y_int_[0]; - ScalarT delta = refframe_ ? ScalarT(0.0) : y_int_[12]; - const auto* y = y_.getData(); - auto* f = f_.getData(); + ScalarT omega = wb_ - mp_ * y_int_[0]; + ScalarT delta = refframe_ ? ScalarT(0.0) : y_int_[12]; // ref common ref motor angle if (refframe_) { - f[0] = omega - y[0]; + *f_ext_[0] += omega - *y_ext_[0]; } else { - f[0] = 0.0; + *f_ext_[0] += 0.0; } // output // current transformed to common frame - f[1] = std::cos(delta) * y_int_[10] - std::sin(delta) * y_int_[11]; - f[2] = std::sin(delta) * y_int_[10] + std::cos(delta) * y_int_[11]; - f_.setDataUpdated(); + *f_ext_[1] += std::cos(delta) * y_int_[10] - std::sin(delta) * y_int_[11]; + *f_ext_[2] += std::sin(delta) * y_int_[10] + std::cos(delta) * y_int_[11]; return 0; } @@ -383,8 +379,7 @@ namespace GridKit }; if (!refframe_) { - const auto* y = y_.getData(); - valtemp.push_back((1.0 / Lc_) * (sin(delta) * static_cast(y[1]) - cos(delta) * static_cast(y[2]))); + valtemp.push_back((1.0 / Lc_) * (sin(delta) * static_cast(*y_ext_[1]) - cos(delta) * static_cast(*y_ext_[2]))); } this->setJacValues(rtemp, ctemp, valtemp); @@ -405,8 +400,7 @@ namespace GridKit }; if (!refframe_) { - const auto* y = y_.getData(); - valtemp.push_back((1.0 / Lc_) * (cos(delta) * static_cast(y[1]) + sin(delta) * static_cast(y[2]))); + valtemp.push_back((1.0 / Lc_) * (cos(delta) * static_cast(*y_ext_[1]) + sin(delta) * static_cast(*y_ext_[2]))); } this->setJacValues(rtemp, ctemp, valtemp); diff --git a/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.hpp b/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.hpp index 505311cea..ab7e340f1 100644 --- a/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.hpp +++ b/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.hpp @@ -47,13 +47,13 @@ namespace GridKit using CircuitComponent::nnz_; using CircuitComponent::time_; using CircuitComponent::alpha_; - using CircuitComponent::y_; + using CircuitComponent::y_ext_; using CircuitComponent::y_int_; - using CircuitComponent::yp_; + using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; using CircuitComponent::abs_tol_; using CircuitComponent::tag_; - using CircuitComponent::f_; + using CircuitComponent::f_ext_; using CircuitComponent::f_int_; using CircuitComponent::g_; using CircuitComponent::yB_; diff --git a/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.cpp b/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.cpp index 41f45e6ae..58a941fe1 100644 --- a/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.cpp +++ b/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.cpp @@ -70,29 +70,22 @@ namespace GridKit template int InductionMotor::evaluateInternalResidual() { - const auto* y = y_.getData(); - - f_int_[0] = (1.0 / 3.0) * (2.0 * y[0] - y[1] - y[2]) - Rs_ * y_int_[0] - (Lls_ + Lms_) * yp_int_[0] - Lms_ * yp_int_[1]; - f_int_[1] = (1.0 / std::sqrt(3.0)) * (-y[1] + y[2]) - Rs_ * y_int_[1] - (Lls_ + Lms_) * yp_int_[1] - Lms_ * yp_int_[0]; - f_int_[2] = (y[0] + y[1] + y[2]) / 3.0 - Rs_ * y_int_[2] - Lls_ * yp_int_[7]; - f_int_[3] = Rr_ * y_int_[3] + (Llr_ + Lms_) * yp_int_[8] + Lms_ * yp_int_[0] - (P_ / 2.0) * y[3] * ((Llr_ + Lms_) * y_int_[4] + Lms_ * y_int_[1]); - f_int_[4] = Rr_ * y_int_[4] + (Llr_ + Lms_) * yp_int_[9] + Lms_ * yp_int_[1] + (P_ / 2.0) * y[3] * ((Llr_ + Lms_) * y_int_[3] + Lms_ * y_int_[0]); + f_int_[0] = (1.0 / 3.0) * (2.0 * *y_ext_[0] - *y_ext_[1] - *y_ext_[2]) - Rs_ * y_int_[0] - (Lls_ + Lms_) * yp_int_[0] - Lms_ * yp_int_[1]; + f_int_[1] = (1.0 / std::sqrt(3.0)) * (-*y_ext_[1] + *y_ext_[2]) - Rs_ * y_int_[1] - (Lls_ + Lms_) * yp_int_[1] - Lms_ * yp_int_[0]; + f_int_[2] = (*y_ext_[0] + *y_ext_[1] + *y_ext_[2]) / 3.0 - Rs_ * y_int_[2] - Lls_ * yp_int_[7]; + f_int_[3] = Rr_ * y_int_[3] + (Llr_ + Lms_) * yp_int_[8] + Lms_ * yp_int_[0] - (P_ / 2.0) * *y_ext_[3] * ((Llr_ + Lms_) * y_int_[4] + Lms_ * y_int_[1]); + f_int_[4] = Rr_ * y_int_[4] + (Llr_ + Lms_) * yp_int_[9] + Lms_ * yp_int_[1] + (P_ / 2.0) * *y_ext_[3] * ((Llr_ + Lms_) * y_int_[3] + Lms_ * y_int_[0]); return 0; } template int InductionMotor::evaluateExternalResidual() { - const auto* y = y_.getData(); - const auto* yp = yp_.getData(); - auto* f = f_.getData(); - - f[0] = y_int_[0] + y_int_[2]; - f[1] = (-1.0 / 2.0) * y_int_[0] - (std::sqrt(3.0) / 2.0) * y_int_[1] + y_int_[2]; - f[2] = (-1.0 / 2.0) * y_int_[0] + (std::sqrt(3.0) / 2.0) * y_int_[1] + y_int_[2]; - f[3] = RJ_ * yp[3] - (3.0 / 4.0) * P_ * Lms_ * (y[5] * y_int_[4] - y_int_[1] * y_int_[3]); - f[4] = yp[4] - y[3]; - f_.setDataUpdated(); + *f_ext_[0] += y_int_[0] + y_int_[2]; + *f_ext_[1] += (-1.0 / 2.0) * y_int_[0] - (std::sqrt(3.0) / 2.0) * y_int_[1] + y_int_[2]; + *f_ext_[2] += (-1.0 / 2.0) * y_int_[0] + (std::sqrt(3.0) / 2.0) * y_int_[1] + y_int_[2]; + *f_ext_[3] += RJ_ * *yp_ext_[3] - (3.0 / 4.0) * P_ * Lms_ * (*y_ext_[5] * y_int_[4] - y_int_[1] * y_int_[3]); + *f_ext_[4] += *yp_ext_[4] - *y_ext_[3]; return 0; } diff --git a/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.hpp b/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.hpp index 89ea72419..122cd4d30 100644 --- a/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.hpp +++ b/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.hpp @@ -25,12 +25,12 @@ namespace GridKit using CircuitComponent::nnz_; using CircuitComponent::time_; using CircuitComponent::alpha_; - using CircuitComponent::y_; + using CircuitComponent::y_ext_; using CircuitComponent::y_int_; - using CircuitComponent::yp_; + using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; using CircuitComponent::tag_; - using CircuitComponent::f_; + using CircuitComponent::f_ext_; using CircuitComponent::f_int_; using CircuitComponent::g_; using CircuitComponent::yB_; diff --git a/GridKit/Model/PowerElectronics/Inductor/Inductor.cpp b/GridKit/Model/PowerElectronics/Inductor/Inductor.cpp index 8e86f5e17..b192cebc5 100644 --- a/GridKit/Model/PowerElectronics/Inductor/Inductor.cpp +++ b/GridKit/Model/PowerElectronics/Inductor/Inductor.cpp @@ -77,22 +77,17 @@ namespace GridKit template int Inductor::evaluateInternalResidual() { - const auto* y = y_.getData(); - - f_int_[0] = -L_ * yp_int_[0] + y[1] - y[0]; + f_int_[0] = -L_ * yp_int_[0] + *y_ext_[1] - *y_ext_[0]; return 0; } template int Inductor::evaluateExternalResidual() { - auto* f = f_.getData(); - // input - f[0] = -y_int_[0]; + *f_ext_[0] += -y_int_[0]; // output - f[1] = y_int_[0]; - f_.setDataUpdated(); + *f_ext_[1] += y_int_[0]; return 0; } diff --git a/GridKit/Model/PowerElectronics/Inductor/Inductor.hpp b/GridKit/Model/PowerElectronics/Inductor/Inductor.hpp index 470a91741..b82ce1070 100644 --- a/GridKit/Model/PowerElectronics/Inductor/Inductor.hpp +++ b/GridKit/Model/PowerElectronics/Inductor/Inductor.hpp @@ -27,13 +27,13 @@ namespace GridKit using CircuitComponent::nnz_; using CircuitComponent::time_; using CircuitComponent::alpha_; - using CircuitComponent::y_; + using CircuitComponent::y_ext_; using CircuitComponent::y_int_; - using CircuitComponent::yp_; + using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; using CircuitComponent::tag_; using CircuitComponent::abs_tol_; - using CircuitComponent::f_; + using CircuitComponent::f_ext_; using CircuitComponent::f_int_; using CircuitComponent::g_; using CircuitComponent::yB_; diff --git a/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.cpp b/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.cpp index b4e2facbc..fcfc4a02d 100644 --- a/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.cpp +++ b/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.cpp @@ -71,21 +71,16 @@ namespace GridKit template int LinearTransformer::evaluateInternalResidual() { - const auto* y = y_.getData(); - - f_int_[0] = y[0] - R0_ * y_int_[0] - L0_ * yp_int_[0] - M_ * yp_int_[1]; - f_int_[1] = y[1] - R1_ * y_int_[1] - M_ * yp_int_[0] - L1_ * yp_int_[1]; + f_int_[0] = *y_ext_[0] - R0_ * y_int_[0] - L0_ * yp_int_[0] - M_ * yp_int_[1]; + f_int_[1] = *y_ext_[1] - R1_ * y_int_[1] - M_ * yp_int_[0] - L1_ * yp_int_[1]; return 0; } template int LinearTransformer::evaluateExternalResidual() { - auto* f = f_.getData(); - - f[0] = y_int_[0]; - f[1] = y_int_[1]; - f_.setDataUpdated(); + *f_ext_[0] += y_int_[0]; + *f_ext_[1] += y_int_[1]; return 0; } diff --git a/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.hpp b/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.hpp index 6e30b185c..62dc84305 100644 --- a/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.hpp +++ b/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.hpp @@ -25,12 +25,12 @@ namespace GridKit using CircuitComponent::nnz_; using CircuitComponent::time_; using CircuitComponent::alpha_; - using CircuitComponent::y_; + using CircuitComponent::y_ext_; using CircuitComponent::y_int_; - using CircuitComponent::yp_; + using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; using CircuitComponent::tag_; - using CircuitComponent::f_; + using CircuitComponent::f_ext_; using CircuitComponent::f_int_; using CircuitComponent::g_; using CircuitComponent::yB_; diff --git a/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.cpp b/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.cpp index bc80a5917..ffc02dfb3 100644 --- a/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.cpp +++ b/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.cpp @@ -91,14 +91,9 @@ namespace GridKit template int MicrogridBusDQ::evaluateExternalResidual() { - const auto* y = y_.getData(); - auto* f = f_.getData(); - // bus voltage - f[0] = -y[0] / RN_; - f[1] = -y[1] / RN_; - - f_.setDataUpdated(); + *f_ext_[0] += -*y_ext_[0] / RN_; + *f_ext_[1] += -*y_ext_[1] / RN_; return 0; } diff --git a/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.hpp b/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.hpp index 05c02d65e..111ca7be8 100644 --- a/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.hpp +++ b/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.hpp @@ -27,13 +27,13 @@ namespace GridKit using CircuitComponent::nnz_; using CircuitComponent::time_; using CircuitComponent::alpha_; - using CircuitComponent::y_; + using CircuitComponent::y_ext_; using CircuitComponent::y_int_; - using CircuitComponent::yp_; + using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; using CircuitComponent::tag_; using CircuitComponent::abs_tol_; - using CircuitComponent::f_; + using CircuitComponent::f_ext_; using CircuitComponent::f_int_; using CircuitComponent::g_; using CircuitComponent::yB_; diff --git a/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.cpp b/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.cpp index fe4915413..9a0df0e53 100644 --- a/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.cpp +++ b/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.cpp @@ -91,10 +91,8 @@ namespace GridKit template int MicrogridLine::evaluateInternalResidual() { - const auto* y = y_.getData(); - - f_int_[0] = -yp_int_[0] - (R_ / L_) * y_int_[0] + y[0] * y_int_[1] + (y[1] - y[3]) / L_; - f_int_[1] = -yp_int_[1] - (R_ / L_) * y_int_[1] - y[0] * y_int_[0] + (y[2] - y[4]) / L_; + f_int_[0] = -yp_int_[0] - (R_ / L_) * y_int_[0] + *y_ext_[0] * y_int_[1] + (*y_ext_[1] - *y_ext_[3]) / L_; + f_int_[1] = -yp_int_[1] - (R_ / L_) * y_int_[1] - *y_ext_[0] * y_int_[0] + (*y_ext_[2] - *y_ext_[4]) / L_; return 0; } @@ -102,20 +100,16 @@ namespace GridKit template int MicrogridLine::evaluateExternalResidual() { - auto* f = f_.getData(); - // ref motor - f[0] = 0.0; + *f_ext_[0] += 0.0; // Port 1 - f[1] = -y_int_[0]; - f[2] = -y_int_[1]; + *f_ext_[1] += -y_int_[0]; + *f_ext_[2] += -y_int_[1]; // Port 2 - f[3] = y_int_[0]; - f[4] = y_int_[1]; - - f_.setDataUpdated(); + *f_ext_[3] += y_int_[0]; + *f_ext_[4] += y_int_[1]; return 0; } @@ -142,13 +136,12 @@ namespace GridKit std::vector rcord(ccord.size(), 5); std::vector vals{}; - const auto* y = y_.getData(); - vals = {static_cast(y_int_[1]), (1.0 / L_), -(1.0 / L_), -(R_ / L_) - alpha_, static_cast(y[0])}; + vals = {static_cast(y_int_[1]), (1.0 / L_), -(1.0 / L_), -(R_ / L_) - alpha_, static_cast(*y_ext_[0])}; this->setJacValues(rcord, ccord, vals); std::vector ccor2{0, 2, 4, 5, 6}; std::fill(rcord.begin(), rcord.end(), 6); - vals = {-static_cast(y_int_[0]), (1.0 / L_), -(1.0 / L_), -static_cast(y[0]), -(R_ / L_) - alpha_}; + vals = {-static_cast(y_int_[0]), (1.0 / L_), -(1.0 / L_), -static_cast(*y_ext_[0]), -(R_ / L_) - alpha_}; this->setJacValues(rcord, ccor2, vals); return 0; diff --git a/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.hpp b/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.hpp index f63826a43..1354a9d9b 100644 --- a/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.hpp +++ b/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.hpp @@ -27,13 +27,13 @@ namespace GridKit using CircuitComponent::nnz_; using CircuitComponent::time_; using CircuitComponent::alpha_; - using CircuitComponent::y_; + using CircuitComponent::y_ext_; using CircuitComponent::y_int_; - using CircuitComponent::yp_; + using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; using CircuitComponent::tag_; using CircuitComponent::abs_tol_; - using CircuitComponent::f_; + using CircuitComponent::f_ext_; using CircuitComponent::f_int_; using CircuitComponent::g_; using CircuitComponent::yB_; diff --git a/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.cpp b/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.cpp index b058e4984..63962d658 100644 --- a/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.cpp +++ b/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.cpp @@ -86,10 +86,8 @@ namespace GridKit template int MicrogridLoad::evaluateInternalResidual() { - const auto* y = y_.getData(); - - f_int_[0] = -yp_int_[0] - (R_ / L_) * y_int_[0] + y[0] * y_int_[1] + y[1] / L_; - f_int_[1] = -yp_int_[1] - (R_ / L_) * y_int_[1] - y[0] * y_int_[0] + y[2] / L_; + f_int_[0] = -yp_int_[0] - (R_ / L_) * y_int_[0] + *y_ext_[0] * y_int_[1] + *y_ext_[1] / L_; + f_int_[1] = -yp_int_[1] - (R_ / L_) * y_int_[1] - *y_ext_[0] * y_int_[0] + *y_ext_[2] / L_; return 0; } @@ -97,18 +95,14 @@ namespace GridKit template int MicrogridLoad::evaluateExternalResidual() { - auto* f = f_.getData(); - // ref motor - f[0] = 0.0; + *f_ext_[0] += 0.0; // only input for loads // input - f[1] = -y_int_[0]; - f[2] = -y_int_[1]; - - f_.setDataUpdated(); + *f_ext_[1] += -y_int_[0]; + *f_ext_[2] += -y_int_[1]; return 0; } @@ -135,13 +129,12 @@ namespace GridKit std::vector rcord(ccord.size(), 3); std::vector vals{}; - const auto* y = y_.getData(); - vals = {static_cast(y_int_[1]), (1.0 / L_), -(R_ / L_) - alpha_, static_cast(y[0])}; + vals = {static_cast(y_int_[1]), (1.0 / L_), -(R_ / L_) - alpha_, static_cast(*y_ext_[0])}; this->setJacValues(rcord, ccord, vals); std::vector ccor2{0, 2, 3, 4}; std::fill(rcord.begin(), rcord.end(), 4); - vals = {-static_cast(y_int_[0]), (1.0 / L_), -static_cast(y[0]), -(R_ / L_) - alpha_}; + vals = {-static_cast(y_int_[0]), (1.0 / L_), -static_cast(*y_ext_[0]), -(R_ / L_) - alpha_}; this->setJacValues(rcord, ccor2, vals); return 0; diff --git a/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.hpp b/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.hpp index dae888a4a..931983d50 100644 --- a/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.hpp +++ b/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.hpp @@ -27,13 +27,13 @@ namespace GridKit using CircuitComponent::nnz_; using CircuitComponent::time_; using CircuitComponent::alpha_; - using CircuitComponent::y_; + using CircuitComponent::y_ext_; using CircuitComponent::y_int_; - using CircuitComponent::yp_; + using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; using CircuitComponent::tag_; using CircuitComponent::abs_tol_; - using CircuitComponent::f_; + using CircuitComponent::f_ext_; using CircuitComponent::f_int_; using CircuitComponent::g_; using CircuitComponent::yB_; diff --git a/GridKit/Model/PowerElectronics/NodeBase.hpp b/GridKit/Model/PowerElectronics/NodeBase.hpp index 04a4c4a69..3f29ec057 100644 --- a/GridKit/Model/PowerElectronics/NodeBase.hpp +++ b/GridKit/Model/PowerElectronics/NodeBase.hpp @@ -4,6 +4,7 @@ #include #include +#include namespace GridKit { @@ -108,9 +109,12 @@ namespace GridKit * @param global_index * @return int */ - int setExternalConnectionNodes(IdxT local_index, IdxT global_index) + int setExternalConnectionNodes(IdxT local_index, CircuitComponent::ExternalConnection global_index) { - connection_nodes_[local_index] = global_index; + y_ext_[local_index] = global_index.y_; + yp_ext_[local_index] = global_index.yp_; + f_ext_[local_index] = global_index.f_; + connection_nodes_[local_index] = global_index.idx_; return 0; } @@ -122,9 +126,14 @@ namespace GridKit * @param local_index index of local value in vector * @return IdxT Index of the same value in the global vector */ - IdxT getNodeConnection(IdxT local_index) const + CircuitComponent::ExternalConnection getNodeConnection(size_t local_index) const { - return connection_nodes_[static_cast(local_index)]; + return typename CircuitComponent::ExternalConnection{ + .y_ = y_ext_[local_index], + .yp_ = yp_ext_[local_index], + .f_ = f_ext_[local_index], + .idx_ = static_cast(connection_nodes_[local_index]), + }; } int allocate() override @@ -140,7 +149,10 @@ namespace GridKit variable_indices_.resize(size); residual_indices_.resize(size); - connection_nodes_ = std::make_unique(size); + y_ext_ = std::make_unique(n_extern_); + yp_ext_ = std::make_unique(n_extern_); + f_ext_ = std::make_unique(n_extern_); + connection_nodes_ = std::make_unique(size); allocated_ = true; return 0; @@ -185,7 +197,7 @@ namespace GridKit return 0; } - private: + protected: IdxT bus_id_{INVALID_INDEX}; size_t n_intern_; @@ -195,11 +207,19 @@ namespace GridKit std::vector variable_indices_; ///< Global (system-level) variable indices std::vector residual_indices_; ///< Global (system-level) residual indices - VectorT y_; - VectorT yp_; std::vector tag_; VectorT abs_tol_; - VectorT f_; + + /// @brief A pointer to the internal variables of this component. + const ScalarT* y_int_; + /// @brief A pointer to the internal derivatives of this component. + const ScalarT* yp_int_; + /// @brief A pointer to the internal residuals of this component + ScalarT* f_int_; + + std::unique_ptr y_ext_; + std::unique_ptr yp_ext_; + std::unique_ptr f_ext_; IdxT* J_rows_buffer_{nullptr}; IdxT* J_cols_buffer_{nullptr}; @@ -219,12 +239,18 @@ namespace GridKit VectorT param_up_{}; VectorT param_lo_{}; - std::unique_ptr connection_nodes_; + std::unique_ptr connection_nodes_; bool allocated_{false}; + private: + VectorT y_; + VectorT yp_; + VectorT f_; + public: - virtual IdxT sizeQuadrature() final + virtual IdxT + sizeQuadrature() final { throw "ERROR: Method not implemented!\n"; return 0; @@ -369,9 +395,6 @@ namespace GridKit private: void allocateVectors(IdxT n) { - y_.resize(n); - yp_.resize(n); - f_.resize(n); abs_tol_.resize(n); } }; diff --git a/GridKit/Model/PowerElectronics/Resistor/Resistor.cpp b/GridKit/Model/PowerElectronics/Resistor/Resistor.cpp index d961867ce..5c6c4a1cb 100644 --- a/GridKit/Model/PowerElectronics/Resistor/Resistor.cpp +++ b/GridKit/Model/PowerElectronics/Resistor/Resistor.cpp @@ -84,14 +84,10 @@ namespace GridKit template int Resistor::evaluateExternalResidual() { - const auto* y = y_.getData(); - auto* f = f_.getData(); - // input - f[0] = (y[0] - y[1]) / R_; + *f_ext_[0] += (*y_ext_[0] - *y_ext_[1]) / R_; // ouput - f[1] = (y[1] - y[0]) / R_; - f_.setDataUpdated(); + *f_ext_[1] += (*y_ext_[1] - *y_ext_[0]) / R_; return 0; } diff --git a/GridKit/Model/PowerElectronics/Resistor/Resistor.hpp b/GridKit/Model/PowerElectronics/Resistor/Resistor.hpp index a6a08b369..540ab4d20 100644 --- a/GridKit/Model/PowerElectronics/Resistor/Resistor.hpp +++ b/GridKit/Model/PowerElectronics/Resistor/Resistor.hpp @@ -27,13 +27,13 @@ namespace GridKit using CircuitComponent::nnz_; using CircuitComponent::time_; using CircuitComponent::alpha_; - using CircuitComponent::y_; + using CircuitComponent::y_ext_; using CircuitComponent::y_int_; - using CircuitComponent::yp_; + using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; using CircuitComponent::tag_; using CircuitComponent::abs_tol_; - using CircuitComponent::f_; + using CircuitComponent::f_ext_; using CircuitComponent::f_int_; using CircuitComponent::g_; using CircuitComponent::yB_; diff --git a/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.cpp b/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.cpp index 6a9ef82dc..892e28022 100644 --- a/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.cpp +++ b/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.cpp @@ -101,11 +101,9 @@ namespace GridKit ScalarT cos23p = std::cos((P_ / 2.0) * y_int_[0] + (2.0 / 3.0) * M_PI); ScalarT sin23p = std::sin((P_ / 2.0) * y_int_[0] + (2.0 / 3.0) * M_PI); - const auto* y = y_.getData(); - - f_int_[0] = (-2.0 / 3.0) * (y[0] * cos1 + y[1] * cos23m + y[2] * cos23p) + Rs_ * y_int_[1] + (Lls_ + Lmq_) * yp_int_[1] + Lmq_ * yp_int_[4] + Lmq_ * yp_int_[5] + y[4] * (P_ / 2.0) * ((Lls_ + Lmd_) * y_int_[2] + Lmd_ * y_int_[6] + Lmd_ * y_int_[7]); - f_int_[1] = (-2.0 / 3.0) * (y[0] * sin1 - y[1] * sin23m - y[2] * sin23p) + Rs_ * y_int_[2] + (Lls_ + Lmd_) * yp_int_[2] + Lmd_ * yp_int_[6] + Lmd_ * yp_int_[7] - y[4] * (P_ / 2.0) * ((Lls_ + Lmq_) * y_int_[1] + Lmq_ * y_int_[4] + Lmq_ * y_int_[5]); - f_int_[2] = (-1.0 / 3.0) * (y[0] + y[1] + y[2]) + Rs_ * y_int_[3] + Lls_ * yp_int_[3]; + f_int_[0] = (-2.0 / 3.0) * (*y_ext_[0] * cos1 + *y_ext_[1] * cos23m + *y_ext_[2] * cos23p) + Rs_ * y_int_[1] + (Lls_ + Lmq_) * yp_int_[1] + Lmq_ * yp_int_[4] + Lmq_ * yp_int_[5] + *y_ext_[4] * (P_ / 2.0) * ((Lls_ + Lmd_) * y_int_[2] + Lmd_ * y_int_[6] + Lmd_ * y_int_[7]); + f_int_[1] = (-2.0 / 3.0) * (*y_ext_[0] * sin1 - *y_ext_[1] * sin23m - *y_ext_[2] * sin23p) + Rs_ * y_int_[2] + (Lls_ + Lmd_) * yp_int_[2] + Lmd_ * yp_int_[6] + Lmd_ * yp_int_[7] - *y_ext_[4] * (P_ / 2.0) * ((Lls_ + Lmq_) * y_int_[1] + Lmq_ * y_int_[4] + Lmq_ * y_int_[5]); + f_int_[2] = (-1.0 / 3.0) * (*y_ext_[0] + *y_ext_[1] + *y_ext_[2]) + Rs_ * y_int_[3] + Lls_ * yp_int_[3]; f_int_[3] = rkq1 * y_int_[4] + (llkq1 + Lmq_) * yp_int_[4] + Lmq_ * yp_int_[1] + Lmq_ * yp_int_[5]; f_int_[4] = rkq1 * y_int_[4] + (llkq1 + Lmq_) * yp_int_[4] + Lmq_ * yp_int_[1] + Lmq_ * yp_int_[5]; return 0; @@ -124,16 +122,11 @@ namespace GridKit ScalarT cos23p = std::cos((P_ / 2.0) * y_int_[0] + (2.0 / 3.0) * M_PI); ScalarT sin23p = std::sin((P_ / 2.0) * y_int_[0] + (2.0 / 3.0) * M_PI); - const auto* y = y_.getData(); - const auto* yp = yp_.getData(); - auto* f = f_.getData(); - - f[0] = y_int_[1] * cos1 + y_int_[2] * sin1 + y_int_[3]; - f[1] = y_int_[1] * cos23m + y_int_[2] * sin23m + y_int_[3]; - f[2] = y_int_[1] * cos23p + y_int_[2] * sin23p + y_int_[3]; - f[3] = RJ_ * yp[4] - (3.0 / 4.0) * P_ * (Lmd_ * y_int_[1] * (y_int_[2] + y_int_[6] + y_int_[7]) - Lmq_ * y_int_[2] * (y_int_[1] + y_int_[4] + y[0])); - f[4] = yp_int_[0] - y[4]; - f_.setDataUpdated(); + *f_ext_[0] += y_int_[1] * cos1 + y_int_[2] * sin1 + y_int_[3]; + *f_ext_[1] += y_int_[1] * cos23m + y_int_[2] * sin23m + y_int_[3]; + *f_ext_[2] += y_int_[1] * cos23p + y_int_[2] * sin23p + y_int_[3]; + *f_ext_[3] += RJ_ * *yp_ext_[4] - (3.0 / 4.0) * P_ * (Lmd_ * y_int_[1] * (y_int_[2] + y_int_[6] + y_int_[7]) - Lmq_ * y_int_[2] * (y_int_[1] + y_int_[4] + *y_ext_[0])); + *f_ext_[4] += yp_int_[0] - *y_ext_[4]; return 0; } diff --git a/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.hpp b/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.hpp index 027efcf21..80b68eed2 100644 --- a/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.hpp +++ b/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.hpp @@ -27,12 +27,12 @@ namespace GridKit using CircuitComponent::nnz_; using CircuitComponent::time_; using CircuitComponent::alpha_; - using CircuitComponent::y_; + using CircuitComponent::y_ext_; using CircuitComponent::y_int_; - using CircuitComponent::yp_; + using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; using CircuitComponent::tag_; - using CircuitComponent::f_; + using CircuitComponent::f_ext_; using CircuitComponent::f_int_; using CircuitComponent::g_; using CircuitComponent::yB_; diff --git a/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp b/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp index 64306207d..77e4f547f 100644 --- a/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp +++ b/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp @@ -4,7 +4,6 @@ #include #include -#include #include #include @@ -18,27 +17,29 @@ namespace GridKit template class PowerElectronicsModel : public CircuitComponent { - using RealT = typename CircuitComponent::RealT; - using CsrMatrixT = typename CircuitComponent::CsrMatrixT; - using component_type = CircuitComponent; - using node_type = PowerElectronics::NodeBase; - - using CircuitComponent::size_; - using CircuitComponent::n_intern_; - using CircuitComponent::n_extern_; - using CircuitComponent::nnz_; - using CircuitComponent::time_; - using CircuitComponent::alpha_; - using CircuitComponent::y_; - using CircuitComponent::y_int_; - using CircuitComponent::yp_; - using CircuitComponent::yp_int_; - using CircuitComponent::f_; - using CircuitComponent::f_int_; - using CircuitComponent::tag_; - using CircuitComponent::abs_tol_; - using CircuitComponent::allocated_; - using CircuitComponent::allocateVectors; + using Base = CircuitComponent; + using RealT = Base::RealT; + using CsrMatrixT = Base::CsrMatrixT; + using component_type = CircuitComponent; + using node_type = PowerElectronics::NodeBase; + using ExternalConnection = Base::ExternalConnection; + + using Base::abs_tol_; + using Base::allocated_; + using Base::allocateVectors; + using Base::alpha_; + using Base::f_ext_; + using Base::f_int_; + using Base::n_extern_; + using Base::n_intern_; + using Base::nnz_; + using Base::size_; + using Base::tag_; + using Base::time_; + using Base::y_ext_; + using Base::y_int_; + using Base::yp_ext_; + using Base::yp_int_; public: /** @@ -144,11 +145,8 @@ namespace GridKit if (!allocated_) { - allocateVectors(static_cast(size_)); + allocateVectors(static_cast(size_), true); // Component and node offsets can change when topology is modified. - y_.setToZero(memory::HOST); - yp_.setToZero(memory::HOST); - f_.setToZero(memory::HOST); abs_tol_.setToZero(memory::HOST); } @@ -162,7 +160,13 @@ namespace GridKit for (size_t i = 0; i < node->getInternalSize(); i++) { - node->setExternalConnectionNodes(i, node_internal_idx); + ExternalConnection node_connection{ + .y_ = y_int_ + node_internal_idx, + .yp_ = yp_int_ + node_internal_idx, + .f_ = f_int_ + node_internal_idx, + .idx_ = static_cast(node_internal_idx)}; + + node->setExternalConnectionNodes(i, node_connection); node_internal_idx++; } } @@ -171,25 +175,22 @@ namespace GridKit { // The offset for each component's internal variables in the system vector. // They start at 0, and are stacked on top of each other. - size_t component_internal_idx = 0; - const auto* y = y_.getData(); - const auto* yp = yp_.getData(); - auto* f = f_.getData(); + size_t component_internal_idx = 0; for (component_type* comp : components_) { comp->allocate(); // Update component internal pointers to their correct offsets - comp->setInternalPointer(&y[component_internal_idx]); - comp->setInternalDerivativePointer(&yp[component_internal_idx]); - comp->setInternalResidualPointer(&f[component_internal_idx]); + comp->setInternalPointer(&y_int_[component_internal_idx]); + comp->setInternalDerivativePointer(&yp_int_[component_internal_idx]); + comp->setInternalResidualPointer(&f_int_[component_internal_idx]); const auto& external_indices = comp->getExternIndices(); for (size_t i = 0; i < comp->size(); i++) { if (!external_indices.contains(i)) { - comp->setExternalConnectionNodes(i, component_internal_idx); + comp->setInternalConnectionNodes(i, component_internal_idx); component_internal_idx++; } } @@ -197,7 +198,6 @@ namespace GridKit } // Evaluate component Jacobians to get sparsity - distributeVectors(); for (component_type* component : components_) { component->evaluateJacobian(); @@ -213,7 +213,7 @@ namespace GridKit for (IdxT i = 0; i < nnz; ++i) { - if (component->getNodeConnection(r[i]) != neg1_ && component->getNodeConnection(c[i]) != neg1_) + if (component->getNodeConnection(r[i]).idx_ != neg1_ && component->getNodeConnection(c[i]).idx_ != neg1_) { ++nnz_dup; } @@ -235,10 +235,10 @@ namespace GridKit for (IdxT i = 0; i < nnz; ++i) { - if (component->getNodeConnection(r[i]) != neg1_ && component->getNodeConnection(c[i]) != neg1_) + if (component->getNodeConnection(r[i]).idx_ != neg1_ && component->getNodeConnection(c[i]).idx_ != neg1_) { - rows_dup[counter] = component->getNodeConnection(r[i]); - cols_dup[counter] = component->getNodeConnection(c[i]); + rows_dup[counter] = component->getNodeConnection(r[i]).idx_; + cols_dup[counter] = component->getNodeConnection(c[i]).idx_; vals_dup[counter] = v[i]; counter++; } @@ -290,48 +290,8 @@ namespace GridKit { component->initialize(); } - y_.setDataUpdated(); - yp_.setDataUpdated(); - this->distributeVectors(); - - return 0; - } - - /** - * @brief Distribute y and y' to each component based of node connection graph - * - * @post Each component has y and y' set - * - * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable - */ - int distributeVectors() - { - const auto* y_system = y_.getData(); - const auto* yp_system = yp_.getData(); - - for (component_type* component : components_) - { - auto* y = component->y().getData(); - auto* yp = component->yp().getData(); - const std::set& externals = component->getExternIndices(); - for (size_t j : externals) - { - if (component->getNodeConnection(j) != neg1_) - { - y[j] = y_system[component->getNodeConnection(j)]; - yp[j] = yp_system[component->getNodeConnection(j)]; - } - else - { - y[j] = 0.0; - yp[j] = 0.0; - } - } - component->y().setDataUpdated(); - component->yp().setDataUpdated(); - } - return 0; + return Base::initialize(); } int tagDifferentiable() final @@ -364,15 +324,11 @@ namespace GridKit */ int evaluateInternalResidual() final { - auto* f = f_.getData(); - - for (IdxT i = 0; i < f_.getSize(); i++) + for (IdxT i = 0; i < size_; i++) { - f[i] = 0.0; + f_int_[i] = 0.0; } - this->distributeVectors(); - // Update system residual vector // Evaluate component internal residuals - this is embarassingly parallel @@ -386,22 +342,8 @@ namespace GridKit { if (int err_code = component->evaluateExternalResidual()) return err_code; - - const auto* residual = component->getResidual().getData(); - const std::set& externals = component->getExternIndices(); - - for (size_t j : externals) - { - //@todo should do a different grounding check - if (component->getNodeConnection(j) != neg1_) - { - f[component->getNodeConnection(j)] += residual[j]; - } - } } - f_.setDataUpdated(); - return 0; } @@ -423,8 +365,6 @@ namespace GridKit */ int evaluateJacobian() final { - distributeVectors(); - // Zero out values RealT* vals = csr_jac_->getValues(); for (IdxT i = 0; i < csr_jac_->getNnz(); ++i) @@ -445,7 +385,7 @@ namespace GridKit for (IdxT i = 0; i < nnz; ++i) { - if (component->getNodeConnection(r[i]) != neg1_ && component->getNodeConnection(c[i]) != neg1_) + if (component->getNodeConnection(r[i]).idx_ != neg1_ && component->getNodeConnection(c[i]).idx_ != neg1_) { vals[map_to_csr_[counter]] += v[i]; ++counter; diff --git a/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.cpp b/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.cpp index 333f44afc..3adbbef58 100644 --- a/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.cpp +++ b/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.cpp @@ -84,13 +84,11 @@ namespace GridKit template int TransmissionLine::evaluateInternalResidual() { - const auto* y = y_.getData(); - // Voltage drop accross terminals - ScalarT V1re = y[0] - y[4]; - ScalarT V1im = y[1] - y[5]; - ScalarT V2re = y[2] - y[6]; - ScalarT V2im = y[3] - y[7]; + ScalarT V1re = *y_ext_[0] - *y_ext_[4]; + ScalarT V1im = *y_ext_[1] - *y_ext_[5]; + ScalarT V2re = *y_ext_[2] - *y_ext_[6]; + ScalarT V2im = *y_ext_[3] - *y_ext_[7]; // Internal variables // row 1 @@ -107,22 +105,18 @@ namespace GridKit template int TransmissionLine::evaluateExternalResidual() { - auto* f = f_.getData(); - // input - f[0] = y_int_[0]; - f[1] = y_int_[1]; + *f_ext_[0] += y_int_[0]; + *f_ext_[1] += y_int_[1]; - f[2] = y_int_[2]; - f[3] = y_int_[3]; + *f_ext_[2] += y_int_[2]; + *f_ext_[3] += y_int_[3]; // ouput - f[4] = -y_int_[0]; - f[5] = -y_int_[1]; - - f[6] = -y_int_[2]; - f[7] = -y_int_[3]; + *f_ext_[4] += -y_int_[0]; + *f_ext_[5] += -y_int_[1]; - f_.setDataUpdated(); + *f_ext_[6] += -y_int_[2]; + *f_ext_[7] += -y_int_[3]; return 0; } diff --git a/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.hpp b/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.hpp index d2441a1c7..091984c89 100644 --- a/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.hpp +++ b/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.hpp @@ -29,12 +29,12 @@ namespace GridKit using CircuitComponent::nnz_; using CircuitComponent::time_; using CircuitComponent::alpha_; - using CircuitComponent::y_; + using CircuitComponent::y_ext_; using CircuitComponent::y_int_; - using CircuitComponent::yp_; + using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; using CircuitComponent::tag_; - using CircuitComponent::f_; + using CircuitComponent::f_ext_; using CircuitComponent::f_int_; using CircuitComponent::g_; using CircuitComponent::yB_; diff --git a/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.cpp b/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.cpp index 1830c5670..9a4accd0b 100644 --- a/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.cpp +++ b/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.cpp @@ -77,23 +77,17 @@ namespace GridKit template int VoltageSource::evaluateInternalResidual() { - // internal - const auto* y = y_.getData(); - - f_int_[0] = y[1] - y[0] - V_; + f_int_[0] = *y_ext_[1] - *y_ext_[0] - V_; return 0; } template int VoltageSource::evaluateExternalResidual() { - auto* f = f_.getData(); - // input - f[0] = -y_int_[0]; + *f_ext_[0] += -y_int_[0]; // ouput - f[1] = y_int_[0]; - f_.setDataUpdated(); + *f_ext_[1] += y_int_[0]; return 0; } diff --git a/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.hpp b/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.hpp index b1509468d..814fa5ec5 100644 --- a/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.hpp +++ b/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.hpp @@ -27,13 +27,13 @@ namespace GridKit using CircuitComponent::nnz_; using CircuitComponent::time_; using CircuitComponent::alpha_; - using CircuitComponent::y_; + using CircuitComponent::y_ext_; using CircuitComponent::y_int_; - using CircuitComponent::yp_; + using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; using CircuitComponent::tag_; using CircuitComponent::abs_tol_; - using CircuitComponent::f_; + using CircuitComponent::f_ext_; using CircuitComponent::f_int_; using CircuitComponent::g_; using CircuitComponent::yB_; diff --git a/examples/PowerElectronics/DistributedGeneratorTest/DGTest.cpp b/examples/PowerElectronics/DistributedGeneratorTest/DGTest.cpp index d8a2ffa20..e6abc497c 100644 --- a/examples/PowerElectronics/DistributedGeneratorTest/DGTest.cpp +++ b/examples/PowerElectronics/DistributedGeneratorTest/DGTest.cpp @@ -11,6 +11,7 @@ #include #include +#include #include /** @@ -74,16 +75,21 @@ int main(int /* argc */, char const** /* argv */) bus.allocate(); dg.allocate(); - std::copy(t2.begin(), t2.end(), dg.y().getData()); - std::copy(t1.begin(), t1.end(), dg.yp().getData()); - std::copy(res.begin(), res.end(), dg.getResidual().getData()); - dg.y().setDataUpdated(); - dg.yp().setDataUpdated(); - dg.getResidual().setDataUpdated(); - auto* dg_res = dg.getResidual().getData(); dg.setInternalPointer(&t2[dg.getExternSize()]); dg.setInternalDerivativePointer(&t1[dg.getExternSize()]); - dg.setInternalResidualPointer(&dg_res[dg.getExternSize()]); + dg.setInternalResidualPointer(&res[dg.getExternSize()]); + + using ExternalConnection = GridKit::CircuitComponent::ExternalConnection; + + for (size_t idx : dg.getExternIndices()) + { + ExternalConnection connection{ + .y_ = &t2[idx], + .yp_ = &t1[idx], + .f_ = &res[idx], + .idx_ = idx}; + dg.setExternalConnectionNodes(idx, connection); + } dg.evaluateResidual(); @@ -108,7 +114,7 @@ int main(int /* argc */, char const** /* argv */) double error_allowed = 10 * std::numeric_limits::epsilon(); for (size_t i = 0; i < true_vec.size(); i++) { - double error = std::abs(true_vec[i] - dg_res[i]) / std::abs(1.0 + true_vec[i]); + double error = std::abs(true_vec[i] - res[i]) / std::abs(1.0 + true_vec[i]); if (error > error_allowed) { std::cout << "Model error for equation " << i << " is: " << error << "\n"; diff --git a/examples/PowerElectronics/Microgrid/Microgrid.cpp b/examples/PowerElectronics/Microgrid/Microgrid.cpp index 9adee78c9..e7ab4f6fd 100644 --- a/examples/PowerElectronics/Microgrid/Microgrid.cpp +++ b/examples/PowerElectronics/Microgrid/Microgrid.cpp @@ -190,7 +190,7 @@ int main(int /* argc */, char const** /* argv */) } // since the intial P_com = 0 - y[dg_signal.getNodeConnection(0)] = parms1.wb_; + y[dg_signal.getNodeConnection(0).idx_] = parms1.wb_; sysmodel->y().setDataUpdated(); sysmodel->yp().setDataUpdated(); diff --git a/examples/PowerElectronics/RLCircuit/RLCircuit.cpp b/examples/PowerElectronics/RLCircuit/RLCircuit.cpp index d5a6cc8f6..a802d84c9 100644 --- a/examples/PowerElectronics/RLCircuit/RLCircuit.cpp +++ b/examples/PowerElectronics/RLCircuit/RLCircuit.cpp @@ -1,11 +1,7 @@ #include -#include -#include -#include #include -#include #include #include diff --git a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp index d91f04fb3..feae5f752 100644 --- a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp +++ b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp @@ -257,7 +257,7 @@ int test(index_type Nsize, real_type error_tol, bool debug_output) } // since the intial P_com = 0, the set the intial vector to the reference frame - y[dg_signal.getNodeConnection(0)] = DG_parms1.wb_; + y[dg_signal.getNodeConnection(0).idx_] = DG_parms1.wb_; sys_model->y().setDataUpdated(); sys_model->yp().setDataUpdated(); diff --git a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp index c9eed0634..762852557 100644 --- a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp +++ b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp @@ -243,7 +243,7 @@ int printMicrogridSystems(index_type N_size) } // since the initial P_com = 0, set the initial vector to the reference frame - y[dg_signal.getNodeConnection(0)] = DG_parms1.wb_; + y[dg_signal.getNodeConnection(0).idx_] = DG_parms1.wb_; sys_model.y().setDataUpdated(); sys_model.yp().setDataUpdated(); From 28673a5835b987d8d8efa3eb23f661bd60fc008e Mon Sep 17 00:00:00 2001 From: Alexander Novotny Date: Fri, 24 Jul 2026 16:55:31 -0400 Subject: [PATCH 02/13] fix memory error --- GridKit/Model/PowerElectronics/NodeBase.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GridKit/Model/PowerElectronics/NodeBase.hpp b/GridKit/Model/PowerElectronics/NodeBase.hpp index 3f29ec057..14a1e888a 100644 --- a/GridKit/Model/PowerElectronics/NodeBase.hpp +++ b/GridKit/Model/PowerElectronics/NodeBase.hpp @@ -149,9 +149,9 @@ namespace GridKit variable_indices_.resize(size); residual_indices_.resize(size); - y_ext_ = std::make_unique(n_extern_); - yp_ext_ = std::make_unique(n_extern_); - f_ext_ = std::make_unique(n_extern_); + y_ext_ = std::make_unique(size); + yp_ext_ = std::make_unique(size); + f_ext_ = std::make_unique(size); connection_nodes_ = std::make_unique(size); allocated_ = true; From 0e81db048ac776bba706dcaf5c6ad26b2d1ba158 Mon Sep 17 00:00:00 2001 From: Alexander Novotny Date: Fri, 24 Jul 2026 16:55:53 -0400 Subject: [PATCH 03/13] Make y_, yp_, and f_ private --- GridKit/Model/PowerElectronics/CircuitComponent.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/GridKit/Model/PowerElectronics/CircuitComponent.hpp b/GridKit/Model/PowerElectronics/CircuitComponent.hpp index f37b715ce..5c20ce3a4 100644 --- a/GridKit/Model/PowerElectronics/CircuitComponent.hpp +++ b/GridKit/Model/PowerElectronics/CircuitComponent.hpp @@ -494,10 +494,6 @@ namespace GridKit std::unique_ptr yp_ext_; std::unique_ptr f_ext_; - VectorT y_; - VectorT yp_; - VectorT f_; - std::vector tag_; VectorT abs_tol_; @@ -520,6 +516,11 @@ namespace GridKit IdxT idc_; bool allocated_{false}; + + private: + VectorT y_; + VectorT yp_; + VectorT f_; }; } // namespace GridKit From 8c50ee85731660e34483e14fb180e4d27e9931cb Mon Sep 17 00:00:00 2001 From: Alexander Novotny Date: Tue, 28 Jul 2026 09:05:43 -0400 Subject: [PATCH 04/13] Change getNodeConnection to just return index for components --- GridKit/Model/PowerElectronics/CircuitComponent.hpp | 11 +++-------- .../PowerElectronics/SystemModelPowerElectronics.hpp | 12 ++++++------ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/GridKit/Model/PowerElectronics/CircuitComponent.hpp b/GridKit/Model/PowerElectronics/CircuitComponent.hpp index 5c20ce3a4..a77302510 100644 --- a/GridKit/Model/PowerElectronics/CircuitComponent.hpp +++ b/GridKit/Model/PowerElectronics/CircuitComponent.hpp @@ -102,14 +102,9 @@ namespace GridKit * @param local_index index of local value in vector * @return size_t Index of the same value in the global vector */ - ExternalConnection getNodeConnection(size_t local_index) const - { - return ExternalConnection{ - .y_ = y_ext_[local_index], - .yp_ = yp_ext_[local_index], - .f_ = f_ext_[local_index], - .idx_ = connection_nodes_[local_index], - }; + IdxT getNodeConnection(size_t local_index) const + { + return connection_nodes_[local_index]; } int initialize() override diff --git a/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp b/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp index 77e4f547f..21520892a 100644 --- a/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp +++ b/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp @@ -213,7 +213,7 @@ namespace GridKit for (IdxT i = 0; i < nnz; ++i) { - if (component->getNodeConnection(r[i]).idx_ != neg1_ && component->getNodeConnection(c[i]).idx_ != neg1_) + if (component->getNodeConnection(r[i]) != neg1_ && component->getNodeConnection(c[i]) != neg1_) { ++nnz_dup; } @@ -226,7 +226,7 @@ namespace GridKit RealT* vals_dup = new RealT[nnz_dup]; IdxT counter = 0; - for (const auto& component : components_) + for (const component_type* component : components_) { const IdxT* r = component->jacobianCooRows(); const IdxT* c = component->jacobianCooCols(); @@ -235,10 +235,10 @@ namespace GridKit for (IdxT i = 0; i < nnz; ++i) { - if (component->getNodeConnection(r[i]).idx_ != neg1_ && component->getNodeConnection(c[i]).idx_ != neg1_) + if (component->getNodeConnection(r[i]) != neg1_ && component->getNodeConnection(c[i]) != neg1_) { - rows_dup[counter] = component->getNodeConnection(r[i]).idx_; - cols_dup[counter] = component->getNodeConnection(c[i]).idx_; + rows_dup[counter] = component->getNodeConnection(r[i]); + cols_dup[counter] = component->getNodeConnection(c[i]); vals_dup[counter] = v[i]; counter++; } @@ -385,7 +385,7 @@ namespace GridKit for (IdxT i = 0; i < nnz; ++i) { - if (component->getNodeConnection(r[i]).idx_ != neg1_ && component->getNodeConnection(c[i]).idx_ != neg1_) + if (component->getNodeConnection(r[i]) != neg1_ && component->getNodeConnection(c[i]) != neg1_) { vals[map_to_csr_[counter]] += v[i]; ++counter; From 6dd431b8625a54c50420b5769fcf2b5cc341694f Mon Sep 17 00:00:00 2001 From: Alexander Novotny Date: Tue, 28 Jul 2026 12:04:20 -0400 Subject: [PATCH 05/13] Documentation --- .../PowerElectronics/Bus/GroundedBus.hpp | 2 - GridKit/Model/PowerElectronics/CMakeLists.txt | 1 + .../PowerElectronics/CircuitComponent.hpp | 105 ++++++++++++++---- .../PowerElectronics/ExternalConnection.hpp | 23 ++++ GridKit/Model/PowerElectronics/NodeBase.hpp | 36 +++--- .../SystemModelPowerElectronics.hpp | 11 +- 6 files changed, 130 insertions(+), 48 deletions(-) create mode 100644 GridKit/Model/PowerElectronics/ExternalConnection.hpp diff --git a/GridKit/Model/PowerElectronics/Bus/GroundedBus.hpp b/GridKit/Model/PowerElectronics/Bus/GroundedBus.hpp index b6a4fe25c..0bd95f8c1 100644 --- a/GridKit/Model/PowerElectronics/Bus/GroundedBus.hpp +++ b/GridKit/Model/PowerElectronics/Bus/GroundedBus.hpp @@ -9,8 +9,6 @@ namespace GridKit template class GroundedBus : public NodeBase { - using ExternalConnection = typename CircuitComponent::ExternalConnection; - using NodeBase::y_ext_; using NodeBase::yp_ext_; using NodeBase::f_ext_; diff --git a/GridKit/Model/PowerElectronics/CMakeLists.txt b/GridKit/Model/PowerElectronics/CMakeLists.txt index 98dce1148..c985d69d6 100644 --- a/GridKit/Model/PowerElectronics/CMakeLists.txt +++ b/GridKit/Model/PowerElectronics/CMakeLists.txt @@ -28,4 +28,5 @@ install( CircuitGraph.hpp SystemModelPowerElectronics.hpp NodeBase.hpp + ExternalConnection.hpp DESTINATION include/GridKit/Model/PowerElectronics) diff --git a/GridKit/Model/PowerElectronics/CircuitComponent.hpp b/GridKit/Model/PowerElectronics/CircuitComponent.hpp index a77302510..5d6659eba 100644 --- a/GridKit/Model/PowerElectronics/CircuitComponent.hpp +++ b/GridKit/Model/PowerElectronics/CircuitComponent.hpp @@ -9,6 +9,7 @@ #include #include +#include namespace GridKit { @@ -55,20 +56,15 @@ namespace GridKit return this->extern_indices_; } - struct ExternalConnection - { - const ScalarT* y_; - const ScalarT* yp_; - ScalarT* f_; - IdxT idx_; - }; - /** - * @brief Create the mappings from local to global indices + * @brief Create the mappings from local to global indices for an internal variable. + * Used for constructing system Jacobians \see connection_nodes_. + * + * @param local_index The index of the local variable + * @param global_index The index of the corresponding system variable. * - * @param local_index - * @param global_index - * @return int + * @pre `local_index` *must* be the index of an internal variable. Using this method for + * an external variable will not properly setup the data pointers for that variable. */ int setInternalConnectionNodes(size_t local_index, size_t global_index) { @@ -78,19 +74,24 @@ namespace GridKit } /** - * @brief Create the mappings from local to global indices + * @brief Create the mappings from local to global indices for an external variable. + * External variables need extra information than internal variables - their data + * pointers \ref y_ext_, \ref yp_ext_, and \ref f_ext_. * - * @param local_index - * @param global_index - * @return int + * @param local_index The index of the local variable + * @param connection The necessary connection information for the variable + * + * @pre `local_index` *must* be the index of an external variable. As of now, using this method + * to set information for a local variable will silently discard the unnecessary information, but + * this may change in the future. */ - int setExternalConnectionNodes(size_t local_index, ExternalConnection global_index) + int setExternalConnectionNodes(size_t local_index, ExternalConnection connection) { assert(extern_indices_.contains(local_index)); - y_ext_[local_index] = global_index.y_; - yp_ext_[local_index] = global_index.yp_; - f_ext_[local_index] = global_index.f_; - connection_nodes_[local_index] = global_index.idx_; + y_ext_[local_index] = connection.y_; + yp_ext_[local_index] = connection.yp_; + f_ext_[local_index] = connection.f_; + connection_nodes_[local_index] = connection.idx_; return 0; } @@ -441,6 +442,18 @@ namespace GridKit protected: /** * @brief Allocate state and residual storage owned by this component. + * + * Most components do not need state and residual storages. The most notable exception + * is currently the system, so a separate flag is provided for the system. + * Systems still can't directly access \ref y_, \ref yp_, and \ref f_, so they need + * their corresponding \ref y_int_, \ref yp_int_, and \ref f_int_ set, since there isn't + * another system above them to set it. + * + * @todo This is a weird exception specifically for systems - and in a hierarchical setting + * will only be needed by the *topmost* system - subsystems shouldn't allocate and should have their + * internal pointers set by the system above them. Ideally we can remove this exception by having + * the integrator allocate these buffers instead of the system and set the internal pointers for the + * topmost system. */ void allocateVectors(IdxT n, bool system = false) { @@ -458,14 +471,23 @@ namespace GridKit } } + /// Number of external variables in this component - ones which are referenced but not owned by this component. size_t n_extern_; + /// Number of internal variables in this component - ones which are only referenced by this component. size_t n_intern_; + /** + * @brief A set of variable indices which correspond to the external variables. Variables indices not in this set are internal. + * + * @invariant Must have a size of n_extern_. Each element must be in the range [0, `size_` - 1]. Not currently verified anywhere. + */ std::set extern_indices_; - ///@todo may want to replace the mapping of connection_nodes to Node objects instead of IdxT. Allows for container free setup + /// A map from local variable indices to system (global) variable indices. Used for Jacobian construction in \ref PowerElectronicsModel::evaluateJacobian(). std::unique_ptr connection_nodes_; protected: + /// The number of variables in this component. Should be equal to \ref n_extern_ plus \ref n_intern_ \see getSize() IdxT size_{0}; + /// The number of nonzero elements in this component's Jacobian. \see nnz() IdxT nnz_{0}; IdxT size_quad_{0}; IdxT size_opt_{0}; @@ -485,8 +507,29 @@ namespace GridKit /// @brief A pointer to the internal residuals of this component ScalarT* f_int_; + /** + * An array of (input) pointers to state values for external variables. + * \note The size of this array is equal to \ref size_, allowing you to index it with the index + * of the variable in question (i.e. consisten with \ref extern_indices_). Therefore, accessing + * and dereferencing the pointer in an internal variable index is undefined behavior. + * \see setExternalConnectionNodes() + */ std::unique_ptr y_ext_; + /** + * An array of (input) pointers to derivative values for external variables. + * \note The size of this array is equal to \ref size_, allowing you to index it with the index + * of the variable in question (i.e. consisten with \ref extern_indices_). Therefore, accessing + * and dereferencing the pointer in an internal variable index is undefined behavior. + * \see setExternalConnectionNodes() + */ std::unique_ptr yp_ext_; + /** + * An array of (output) pointers to residuals for external variables. + * \note The size of this array is equal to \ref size_, allowing you to index it with the index + * of the variable in question (i.e. consisten with \ref extern_indices_). Therefore, accessing + * and dereferencing the pointer in an internal variable index is undefined behavior. + * \see setExternalConnectionNodes() + */ std::unique_ptr f_ext_; std::vector tag_; @@ -513,8 +556,26 @@ namespace GridKit bool allocated_{false}; private: + /** + * The internal buffer for state for the component. For most components, it will be empty and shouldn't be accessed. + * Instead use \ref y_int_ for an internal variable or \ref y_ext_ for an external variable, respectively. + * For components which want an internal buffer (such as a system), make sure that \ref y_int_ points here. + * \see allocateVectors() + */ VectorT y_; + /** + * The internal buffer for derivatives for the component. For most components, it will be empty and shouldn't be accessed. + * Instead use \ref yp_int_ for an internal variable or \ref yp_ext_ for an external variable, respectively. + * For components which want an internal buffer (such as a system), make sure that \ref yp_int_ points here. + * \see allocateVectors() + */ VectorT yp_; + /** + * The internal buffer for state for the component. For most components, it will be empty and shouldn't be accessed. + * Instead use \ref f_int_ for an internal variable or \ref f_ext_ for an external variable, respectively. + * For components which want an internal buffer (such as a system), make sure that \ref f_int_ points here. + * \see allocateVectors() + */ VectorT f_; }; diff --git a/GridKit/Model/PowerElectronics/ExternalConnection.hpp b/GridKit/Model/PowerElectronics/ExternalConnection.hpp new file mode 100644 index 000000000..e5dc4675e --- /dev/null +++ b/GridKit/Model/PowerElectronics/ExternalConnection.hpp @@ -0,0 +1,23 @@ +#pragma once + +namespace GridKit +{ + /** + * @brief The connection of a component's external variable to its system. + * Allows the component to access data about that external variable and allows + * the system to construct Jacobian information about that variable. + * @see CircuitComponent::setExternalConnectionNodes() + */ + template + struct ExternalConnection + { + /// A pointer to the state value of the variable. \see CircuitComponent::y_ext_ + const ScalarT* y_; + /// A pointer to the derivative value of the variable. \see CircuitComponent::yp_ext_ + const ScalarT* yp_; + /// A pointer to the residual buffer of the variable. \see CircuitComponent::f_ext_ + ScalarT* f_; + /// The corresponding system variable index. \see CircuitComponent::connection_nodes_ + IdxT idx_; + }; +} // namespace GridKit \ No newline at end of file diff --git a/GridKit/Model/PowerElectronics/NodeBase.hpp b/GridKit/Model/PowerElectronics/NodeBase.hpp index 14a1e888a..a3fd48e15 100644 --- a/GridKit/Model/PowerElectronics/NodeBase.hpp +++ b/GridKit/Model/PowerElectronics/NodeBase.hpp @@ -4,7 +4,7 @@ #include #include -#include +#include namespace GridKit { @@ -103,32 +103,32 @@ namespace GridKit } /** - * @brief Create the mappings from local to global indices + * @brief Create the mappings from local to global indices for a node variable (either internal or external), + * to be used from an attached component. \see CircuitComponent::setExternalConnectionNodes() * - * @param local_index - * @param global_index - * @return int + * @param local_index The index of the local variable + * @param connection The necessary connection information for the variable + * + * @pre `local_index` *must* be the index of an external variable. As of now, using this method + * to set information for a local variable will silently discard the unnecessary information, but + * this may change in the future. */ - int setExternalConnectionNodes(IdxT local_index, CircuitComponent::ExternalConnection global_index) + int setExternalConnectionNodes(IdxT local_index, ExternalConnection connection) { - y_ext_[local_index] = global_index.y_; - yp_ext_[local_index] = global_index.yp_; - f_ext_[local_index] = global_index.f_; - connection_nodes_[local_index] = global_index.idx_; + y_ext_[local_index] = connection.y_; + yp_ext_[local_index] = connection.yp_; + f_ext_[local_index] = connection.f_; + connection_nodes_[local_index] = connection.idx_; return 0; } /** - * @brief Given the location of value in the local vector map to global index - * - * f(local_index) = global_index - * - * @param local_index index of local value in vector - * @return IdxT Index of the same value in the global vector + * @brief Get connection information for a particular variable, to be consumed by an attached + * component so they can properly access their externals. */ - CircuitComponent::ExternalConnection getNodeConnection(size_t local_index) const + ExternalConnection getNodeConnection(size_t local_index) const { - return typename CircuitComponent::ExternalConnection{ + return ExternalConnection{ .y_ = y_ext_[local_index], .yp_ = yp_ext_[local_index], .f_ = f_ext_[local_index], diff --git a/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp b/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp index 21520892a..5d1d8bf09 100644 --- a/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp +++ b/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp @@ -17,12 +17,11 @@ namespace GridKit template class PowerElectronicsModel : public CircuitComponent { - using Base = CircuitComponent; - using RealT = Base::RealT; - using CsrMatrixT = Base::CsrMatrixT; - using component_type = CircuitComponent; - using node_type = PowerElectronics::NodeBase; - using ExternalConnection = Base::ExternalConnection; + using Base = CircuitComponent; + using RealT = Base::RealT; + using CsrMatrixT = Base::CsrMatrixT; + using component_type = CircuitComponent; + using node_type = PowerElectronics::NodeBase; using Base::abs_tol_; using Base::allocated_; From f3ad96b0509abafdf539834d612b94efab6c0cb0 Mon Sep 17 00:00:00 2001 From: Alexander Novotny Date: Tue, 28 Jul 2026 12:05:49 -0400 Subject: [PATCH 06/13] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f084bdaeb..816aa1749 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,7 @@ - Clarified naming conventions for macros. - Added `dt_fixed`, `rel_tol`, and `abs_tol` options to phasor dynamics solver JSON files and renamed the `dt` option to `dt_monitor`. - Added EMT model and operator documentation. +- Remove unnecessary data copying while evaluating `PowerElectronics` models, speeding up large simulations by up to 3x ## v0.1 From b718509f50b8a8a4a470a40f0e76396808404462 Mon Sep 17 00:00:00 2001 From: alexander-novo Date: Tue, 28 Jul 2026 16:08:40 +0000 Subject: [PATCH 07/13] Apply pre-commit fixes --- GridKit/Model/PowerElectronics/ExternalConnection.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GridKit/Model/PowerElectronics/ExternalConnection.hpp b/GridKit/Model/PowerElectronics/ExternalConnection.hpp index e5dc4675e..5edf9a7e8 100644 --- a/GridKit/Model/PowerElectronics/ExternalConnection.hpp +++ b/GridKit/Model/PowerElectronics/ExternalConnection.hpp @@ -20,4 +20,4 @@ namespace GridKit /// The corresponding system variable index. \see CircuitComponent::connection_nodes_ IdxT idx_; }; -} // namespace GridKit \ No newline at end of file +} // namespace GridKit From 8fd46c90a702805b7ce62feec7e20e7fb7204226 Mon Sep 17 00:00:00 2001 From: Alexander Novotny Date: Tue, 28 Jul 2026 12:10:18 -0400 Subject: [PATCH 08/13] Update DGTest example --- examples/PowerElectronics/DistributedGeneratorTest/DGTest.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/PowerElectronics/DistributedGeneratorTest/DGTest.cpp b/examples/PowerElectronics/DistributedGeneratorTest/DGTest.cpp index e6abc497c..286320844 100644 --- a/examples/PowerElectronics/DistributedGeneratorTest/DGTest.cpp +++ b/examples/PowerElectronics/DistributedGeneratorTest/DGTest.cpp @@ -79,11 +79,9 @@ int main(int /* argc */, char const** /* argv */) dg.setInternalDerivativePointer(&t1[dg.getExternSize()]); dg.setInternalResidualPointer(&res[dg.getExternSize()]); - using ExternalConnection = GridKit::CircuitComponent::ExternalConnection; - for (size_t idx : dg.getExternIndices()) { - ExternalConnection connection{ + GridKit::ExternalConnection connection{ .y_ = &t2[idx], .yp_ = &t1[idx], .f_ = &res[idx], From dc7948ad34a371780231426e6f83d2cda9e06687 Mon Sep 17 00:00:00 2001 From: Alexander Novotny Date: Tue, 28 Jul 2026 12:11:38 -0400 Subject: [PATCH 09/13] Remove unnecessary branch --- .../DistributedGenerator/DistributedGenerator.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.cpp b/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.cpp index 0a7f7c373..baaf6b216 100644 --- a/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.cpp +++ b/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.cpp @@ -161,10 +161,6 @@ namespace GridKit { *f_ext_[0] += omega - *y_ext_[0]; } - else - { - *f_ext_[0] += 0.0; - } // output // current transformed to common frame From e6282c090df8355bcf043c2a8b3fff4a7b7f1bd5 Mon Sep 17 00:00:00 2001 From: Alexander Novotny Date: Tue, 28 Jul 2026 12:15:55 -0400 Subject: [PATCH 10/13] [skip ci] Add comment about INVALID_INDEX --- GridKit/Model/PowerElectronics/CircuitComponent.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/GridKit/Model/PowerElectronics/CircuitComponent.hpp b/GridKit/Model/PowerElectronics/CircuitComponent.hpp index 5d6659eba..e7cf6a4f5 100644 --- a/GridKit/Model/PowerElectronics/CircuitComponent.hpp +++ b/GridKit/Model/PowerElectronics/CircuitComponent.hpp @@ -481,7 +481,12 @@ namespace GridKit * @invariant Must have a size of n_extern_. Each element must be in the range [0, `size_` - 1]. Not currently verified anywhere. */ std::set extern_indices_; - /// A map from local variable indices to system (global) variable indices. Used for Jacobian construction in \ref PowerElectronicsModel::evaluateJacobian(). + /** + * @brief A map from local variable indices to system (global) variable indices. Used for Jacobian construction in + * \ref PowerElectronicsModel::evaluateJacobian(). + * @note If a variable does not map to a corresponding variable in the system (such as with reference nodes), a special + * sentinel value of \ref INVALID_INDEX is used. During Jacobian construction, such rows and columns will be pruned. + */ std::unique_ptr connection_nodes_; protected: From 1397a412cc36a298e1faa5d5487e0f3fa8b1d978 Mon Sep 17 00:00:00 2001 From: Alexander Novotny Date: Tue, 28 Jul 2026 12:17:35 -0400 Subject: [PATCH 11/13] Fix mis-compilation on clang --- GridKit/Model/PowerElectronics/Bus/GroundedBus.hpp | 2 +- GridKit/Model/PowerElectronics/NodeBase.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GridKit/Model/PowerElectronics/Bus/GroundedBus.hpp b/GridKit/Model/PowerElectronics/Bus/GroundedBus.hpp index 0bd95f8c1..2020dfa86 100644 --- a/GridKit/Model/PowerElectronics/Bus/GroundedBus.hpp +++ b/GridKit/Model/PowerElectronics/Bus/GroundedBus.hpp @@ -24,7 +24,7 @@ namespace GridKit if (int err_code = NodeBase::allocate()) return err_code; - this->setExternalConnectionNodes(0, ExternalConnection{.y_ = &voltage_, .yp_ = &dummy_, .f_ = &dummy_, .idx_ = INVALID_INDEX}); + this->setExternalConnectionNodes(0, ExternalConnection{.y_ = &voltage_, .yp_ = &dummy_, .f_ = &dummy_, .idx_ = INVALID_INDEX}); return 0; } diff --git a/GridKit/Model/PowerElectronics/NodeBase.hpp b/GridKit/Model/PowerElectronics/NodeBase.hpp index a3fd48e15..454c100c7 100644 --- a/GridKit/Model/PowerElectronics/NodeBase.hpp +++ b/GridKit/Model/PowerElectronics/NodeBase.hpp @@ -128,7 +128,7 @@ namespace GridKit */ ExternalConnection getNodeConnection(size_t local_index) const { - return ExternalConnection{ + return ExternalConnection{ .y_ = y_ext_[local_index], .yp_ = yp_ext_[local_index], .f_ = f_ext_[local_index], From 1af6d9140ae03b8cf68613d4c29186fd77d1880e Mon Sep 17 00:00:00 2001 From: Alexander Novotny Date: Tue, 28 Jul 2026 12:46:47 -0400 Subject: [PATCH 12/13] Fix another clang compiler issue --- GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp b/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp index 5d1d8bf09..654e2fb84 100644 --- a/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp +++ b/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp @@ -159,7 +159,7 @@ namespace GridKit for (size_t i = 0; i < node->getInternalSize(); i++) { - ExternalConnection node_connection{ + ExternalConnection node_connection{ .y_ = y_int_ + node_internal_idx, .yp_ = yp_int_ + node_internal_idx, .f_ = f_int_ + node_internal_idx, From 7d12ecc424a586a79a99680fe39dd425a65d6e74 Mon Sep 17 00:00:00 2001 From: Alexander Novotny Date: Thu, 30 Jul 2026 11:51:11 -0400 Subject: [PATCH 13/13] Change connection_nodes_ to be IdxT This makes more sense now that connection_nodes_ is only used to construct system Jacobians - the intended purpose of IdxT. --- .../Model/PowerElectronics/CircuitComponent.hpp | 14 +++++++------- GridKit/Model/PowerElectronics/NodeBase.hpp | 6 +++--- .../SystemModelPowerElectronics.hpp | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/GridKit/Model/PowerElectronics/CircuitComponent.hpp b/GridKit/Model/PowerElectronics/CircuitComponent.hpp index e7cf6a4f5..ac7312a67 100644 --- a/GridKit/Model/PowerElectronics/CircuitComponent.hpp +++ b/GridKit/Model/PowerElectronics/CircuitComponent.hpp @@ -66,9 +66,9 @@ namespace GridKit * @pre `local_index` *must* be the index of an internal variable. Using this method for * an external variable will not properly setup the data pointers for that variable. */ - int setInternalConnectionNodes(size_t local_index, size_t global_index) + int setInternalConnectionNodes(size_t local_index, IdxT global_index) { - assert(!extern_indices_.contains(local_index)); + assert(!extern_indices_.contains(static_cast(local_index))); connection_nodes_[local_index] = global_index; return 0; } @@ -135,7 +135,7 @@ namespace GridKit 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_)); + connection_nodes_ = std::make_unique(static_cast(size_)); if (!allocated_) { @@ -472,22 +472,22 @@ namespace GridKit } /// Number of external variables in this component - ones which are referenced but not owned by this component. - size_t n_extern_; + size_t n_extern_; /// Number of internal variables in this component - ones which are only referenced by this component. - size_t n_intern_; + size_t n_intern_; /** * @brief A set of variable indices which correspond to the external variables. Variables indices not in this set are internal. * * @invariant Must have a size of n_extern_. Each element must be in the range [0, `size_` - 1]. Not currently verified anywhere. */ - std::set extern_indices_; + std::set extern_indices_; /** * @brief A map from local variable indices to system (global) variable indices. Used for Jacobian construction in * \ref PowerElectronicsModel::evaluateJacobian(). * @note If a variable does not map to a corresponding variable in the system (such as with reference nodes), a special * sentinel value of \ref INVALID_INDEX is used. During Jacobian construction, such rows and columns will be pruned. */ - std::unique_ptr connection_nodes_; + std::unique_ptr connection_nodes_; protected: /// The number of variables in this component. Should be equal to \ref n_extern_ plus \ref n_intern_ \see getSize() diff --git a/GridKit/Model/PowerElectronics/NodeBase.hpp b/GridKit/Model/PowerElectronics/NodeBase.hpp index 454c100c7..3c7f7c80b 100644 --- a/GridKit/Model/PowerElectronics/NodeBase.hpp +++ b/GridKit/Model/PowerElectronics/NodeBase.hpp @@ -132,7 +132,7 @@ namespace GridKit .y_ = y_ext_[local_index], .yp_ = yp_ext_[local_index], .f_ = f_ext_[local_index], - .idx_ = static_cast(connection_nodes_[local_index]), + .idx_ = connection_nodes_[local_index], }; } @@ -152,7 +152,7 @@ namespace GridKit y_ext_ = std::make_unique(size); yp_ext_ = std::make_unique(size); f_ext_ = std::make_unique(size); - connection_nodes_ = std::make_unique(size); + connection_nodes_ = std::make_unique(size); allocated_ = true; return 0; @@ -239,7 +239,7 @@ namespace GridKit VectorT param_up_{}; VectorT param_lo_{}; - std::unique_ptr connection_nodes_; + std::unique_ptr connection_nodes_; bool allocated_{false}; diff --git a/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp b/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp index 654e2fb84..174e28568 100644 --- a/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp +++ b/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp @@ -185,7 +185,7 @@ namespace GridKit comp->setInternalResidualPointer(&f_int_[component_internal_idx]); const auto& external_indices = comp->getExternIndices(); - for (size_t i = 0; i < comp->size(); i++) + for (IdxT i = 0; i < comp->size(); i++) { if (!external_indices.contains(i)) {