From 962646c96ed97e884e9d9f41740bc282505d825a Mon Sep 17 00:00:00 2001 From: Alexander Novotny Date: Thu, 8 Jan 2026 16:04:56 -0500 Subject: [PATCH 1/4] Change connection_nodes_ to be an array --- .../PowerElectronics/CircuitComponent.hpp | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/GridKit/Model/PowerElectronics/CircuitComponent.hpp b/GridKit/Model/PowerElectronics/CircuitComponent.hpp index 9d7f53ee..d94e042d 100644 --- a/GridKit/Model/PowerElectronics/CircuitComponent.hpp +++ b/GridKit/Model/PowerElectronics/CircuitComponent.hpp @@ -21,8 +21,15 @@ namespace GridKit using RealT = typename Model::Evaluator::RealT; using MatrixT = typename Model::Evaluator::MatrixT; - CircuitComponent() = default; - ~CircuitComponent() = default; + CircuitComponent() = default; + + ~CircuitComponent() + { + if (connection_nodes_ != nullptr) + { + delete[] connection_nodes_; + } + }; void updateTime(RealT t, RealT a) { @@ -59,6 +66,11 @@ namespace GridKit */ int setExternalConnectionNodes(IdxT local_index, IdxT global_index) { + if (connection_nodes_ == nullptr) + { + connection_nodes_ = new IdxT[size_]; + } + connection_nodes_[local_index] = global_index; return 0; } @@ -73,7 +85,7 @@ namespace GridKit */ IdxT getNodeConnection(IdxT local_index) { - return connection_nodes_.at(local_index); + return connection_nodes_[local_index]; } public: @@ -245,11 +257,11 @@ namespace GridKit } protected: - 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::map connection_nodes_; + IdxT* connection_nodes_ = nullptr; protected: IdxT size_{0}; From 726445669b75c15ece46418969de2c8b8c0abaff Mon Sep 17 00:00:00 2001 From: Alexander Novotny Date: Thu, 8 Jan 2026 16:19:40 -0500 Subject: [PATCH 2/4] Add final and const to various functions in PE Allow for (hopefully) better inlining and LICM by the optimizer when we're pointing to a CircuitComponent or PowerElectronicsModel --- .../PowerElectronics/CircuitComponent.hpp | 93 ++++++++++++------- .../SystemModelPowerElectronics.hpp | 20 ++-- 2 files changed, 68 insertions(+), 45 deletions(-) diff --git a/GridKit/Model/PowerElectronics/CircuitComponent.hpp b/GridKit/Model/PowerElectronics/CircuitComponent.hpp index d94e042d..55bcf3f1 100644 --- a/GridKit/Model/PowerElectronics/CircuitComponent.hpp +++ b/GridKit/Model/PowerElectronics/CircuitComponent.hpp @@ -31,7 +31,10 @@ namespace GridKit } }; - void updateTime(RealT t, RealT a) + /** + * @note Cannot be marked final, since it is overriden to recurse in the system model. + */ + void updateTime(RealT t, RealT a) override { this->time_ = t; this->alpha_ = a; @@ -83,175 +86,195 @@ 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) + IdxT getNodeConnection(IdxT local_index) const { return connection_nodes_[local_index]; } public: - virtual IdxT size() + IdxT size() final { return size_; } - virtual IdxT nnz() + IdxT size() const + { + return size_; + } + + IdxT nnz() final + { + return nnz_; + } + + IdxT nnz() const { return nnz_; } - virtual IdxT sizeQuadrature() + IdxT sizeQuadrature() final + { + return size_quad_; + } + + IdxT sizeQuadrature() const { return size_quad_; } - virtual IdxT sizeParams() + IdxT sizeParams() final + { + return size_opt_; + } + + IdxT sizeParams() const { return size_opt_; } - virtual void setTolerances(RealT& rel_tol, RealT& abs_tol) const + void setTolerances(RealT& rel_tol, RealT& abs_tol) const final { rel_tol = rel_tol_; abs_tol = abs_tol_; } - virtual void setMaxSteps(IdxT& msa) const + void setMaxSteps(IdxT& msa) const final { msa = max_steps_; } - std::vector& y() + std::vector& y() final { return y_; } - const std::vector& y() const + const std::vector& y() const final { return y_; } - std::vector& yp() + std::vector& yp() final { return yp_; } - const std::vector& yp() const + const std::vector& yp() const final { return yp_; } - std::vector& tag() + std::vector& tag() final { return tag_; } - const std::vector& tag() const + const std::vector& tag() const final { return tag_; } - std::vector& yB() + std::vector& yB() final { return yB_; } - const std::vector& yB() const + const std::vector& yB() const final { return yB_; } - std::vector& ypB() + std::vector& ypB() final { return ypB_; } - const std::vector& ypB() const + const std::vector& ypB() const final { return ypB_; } - std::vector& param() + std::vector& param() final { return param_; } - const std::vector& param() const + const std::vector& param() const final { return param_; } - std::vector& param_up() + std::vector& param_up() final { return param_up_; } - const std::vector& param_up() const + const std::vector& param_up() const final { return param_up_; } - std::vector& param_lo() + std::vector& param_lo() final { return param_lo_; } - const std::vector& param_lo() const + const std::vector& param_lo() const final { return param_lo_; } - std::vector& getResidual() + std::vector& getResidual() final { return f_; } - const std::vector& getResidual() const + const std::vector& getResidual() const final { return f_; } - MatrixT& getJacobian() + MatrixT& getJacobian() final { return jac_; } - const MatrixT& getJacobian() const + const MatrixT& getJacobian() const final { return jac_; } - std::vector& getIntegrand() + std::vector& getIntegrand() final { return g_; } - const std::vector& getIntegrand() const + const std::vector& getIntegrand() const final { return g_; } - std::vector& getAdjointResidual() + std::vector& getAdjointResidual() final { return fB_; } - const std::vector& getAdjointResidual() const + const std::vector& getAdjointResidual() const final { return fB_; } - std::vector& getAdjointIntegrand() + std::vector& getAdjointIntegrand() final { return gB_; } - const std::vector& getAdjointIntegrand() const + const std::vector& getAdjointIntegrand() const final { return gB_; } //@todo Fix ID naming - IdxT getIDcomponent() + IdxT getIDcomponent() const { return idc_; } diff --git a/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp b/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp index 736f9d00..e756832d 100644 --- a/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp +++ b/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp @@ -133,7 +133,7 @@ namespace GridKit * * @return int */ - int allocate() + int allocate() final { return 1; } @@ -145,7 +145,7 @@ namespace GridKit * @return true if all components have jacobian * @return false otherwise */ - bool hasJacobian() + bool hasJacobian() final { if (!this->use_jac_) return false; @@ -192,7 +192,7 @@ namespace GridKit * * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable */ - int initialize() + int initialize() final { // Initialize components for (const auto& component : components_) @@ -242,7 +242,7 @@ namespace GridKit * * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable */ - int evaluateResidual() + int evaluateResidual() final { for (IdxT i = 0; i < this->f_.size(); i++) { @@ -278,7 +278,7 @@ namespace GridKit * * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable */ - int evaluateJacobian() + int evaluateJacobian() final { jac_.zeroMatrix(); distributeVectors(); @@ -320,7 +320,7 @@ namespace GridKit /** * @brief Evaluate integrands for the system quadratures. */ - int evaluateIntegrand() + int evaluateIntegrand() final { return 0; @@ -332,7 +332,7 @@ namespace GridKit * Updates variables and optimization parameters, then initializes * adjoints locally and copies them to the system adjoint vector. */ - int initializeAdjoint() + int initializeAdjoint() final { return 0; } @@ -342,7 +342,7 @@ namespace GridKit * * */ - int evaluateAdjointResidual() + int evaluateAdjointResidual() final { return 0; } @@ -352,7 +352,7 @@ namespace GridKit * * */ - int evaluateAdjointIntegrand() + int evaluateAdjointIntegrand() final { return 0; } @@ -363,7 +363,7 @@ namespace GridKit * @param t * @param a */ - void updateTime(RealT t, RealT a) + void updateTime(RealT t, RealT a) final { for (const auto& component : components_) { From 03e199318f9d975099b487002194360311cd793a Mon Sep 17 00:00:00 2001 From: Alexander Novotny Date: Thu, 8 Jan 2026 16:34:44 -0500 Subject: [PATCH 3/4] Perform manual LICM on some hot loops in PowerElectronicsModel --- .../SystemModelPowerElectronics.hpp | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp b/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp index e756832d..1bffd0d8 100644 --- a/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp +++ b/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp @@ -215,17 +215,21 @@ namespace GridKit { for (const auto& component : components_) { - for (IdxT j = 0; j < component->size(); ++j) + IdxT size = component->size(); + std::vector& y = component->y(); + std::vector& yp = component->yp(); + + for (IdxT j = 0; j < size; ++j) { if (component->getNodeConnection(j) != neg1_) { - component->y()[j] = y_[component->getNodeConnection(j)]; - component->yp()[j] = yp_[component->getNodeConnection(j)]; + y[j] = y_[component->getNodeConnection(j)]; + yp[j] = yp_[component->getNodeConnection(j)]; } else { - component->y()[j] = 0.0; - component->yp()[j] = 0.0; + y[j] = 0.0; + yp[j] = 0.0; } } } @@ -257,12 +261,15 @@ namespace GridKit { // TODO:check return type component->evaluateResidual(); - for (IdxT j = 0; j < component->size(); ++j) + + IdxT size = component->size(); + const std::vector& residual = component->getResidual(); + for (IdxT j = 0; j < size; ++j) { //@todo should do a different grounding check if (component->getNodeConnection(j) != neg1_) { - f_[component->getNodeConnection(j)] += component->getResidual()[j]; + f_[component->getNodeConnection(j)] += residual[j]; } } } From cefbb7c4900f3f72d5b82705c566aedd22a6b5ee Mon Sep 17 00:00:00 2001 From: Alexander Novotny Date: Thu, 8 Jan 2026 17:04:30 -0500 Subject: [PATCH 4/4] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca382a44..b8dfddd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ - Added a header file defining common math functions (e.g., sigmoid) to be used throughout the code. - Added capability to print monitored variables in multiple formats, triggered from `Ida::runSimulation`. - Added IDA statistics object which can be accumulated over multiple simulations. +- Minor performance improvements to residual evaluation in PowerElectronics module. ## v0.1