From fa14a0e64facbd7ed846fbc001c98ded709d89f3 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Tue, 21 Apr 2026 18:11:16 +0000 Subject: [PATCH 01/34] Work in progress code for cosim integration --- GridKit/Model/PartitionEvaluator.hpp | 282 ++++++++++++++++++ .../Solver/Dynamic/MultiStageCosimulation.cpp | 124 ++++++++ .../Solver/Dynamic/MultiStageCosimulation.hpp | 133 +++++++++ 3 files changed, 539 insertions(+) create mode 100644 GridKit/Model/PartitionEvaluator.hpp create mode 100644 GridKit/Solver/Dynamic/MultiStageCosimulation.cpp create mode 100644 GridKit/Solver/Dynamic/MultiStageCosimulation.hpp diff --git a/GridKit/Model/PartitionEvaluator.hpp b/GridKit/Model/PartitionEvaluator.hpp new file mode 100644 index 000000000..96d906ea3 --- /dev/null +++ b/GridKit/Model/PartitionEvaluator.hpp @@ -0,0 +1,282 @@ +#pragma once + +#include + +#include "Evaluator.hpp" + +namespace GridKit +{ + namespace Model + { + + template + class PartitionEvaluator : public Evaluator + { + public: + using Base = Evaluator; + using RealT = typename Base::RealT; + using MatrixT = typename Base::MatrixT; + using CsrMatrixT = typename Base::CsrMatrixT; + + using ForcingFunc = std::function; + + private: + std::vector y_; + std::vector yp_; + std::vector yB_; + std::vector ypB_; + std::vector param_; + std::vector param_up_; + std::vector param_lo_; + std::vector residual_; + std::vector integrand_; + std::vector adj_integrand_; + std::vector adj_residual_; + std::vector tag_; + + MatrixT jacobian_; + + std::vector coupling_; + std::vector forcing_; + + public: + int allocate() override + { + return 0; + } + + int initialize() override + { + return 0; + } + + int tagDifferentiable() override + { + return 0; + } + + int evaluateResidual() override + { + return 0; + } + + int evaluateJacobian() override + { + return 0; + } + + int evaluateIntegrand() override + { + return 0; + } + + int initializeAdjoint() override + { + return 0; + } + + int evaluateAdjointResidual() override + { + return 0; + } + + int evaluateAdjointIntegrand() override + { + return 0; + } + + IdxT size() override + { + return 0; + } + + IdxT nnz() override + { + return 0; + } + + bool hasJacobian() override + { + return false; + } + + IdxT sizeQuadrature() override + { + return 0; + } + + IdxT sizeParams() override + { + return 0; + } + + void updateTime(RealT, RealT) override + { + } + + void setTolerances(RealT&, RealT&) const override + { + } + + void setMaxSteps(IdxT&) const override + { + } + + std::vector& y() override + { + return y_; + } + + const std::vector& y() const override + { + return y_; + } + + std::vector& yp() override + { + return yp_; + } + + const std::vector& yp() const override + { + return yp_; + } + + std::vector& tag() override + { + return tag_; + } + + const std::vector& tag() const override + { + return tag_; + } + + std::vector& yB() override + { + return yB_; + } + + const std::vector& yB() const override + { + return yB_; + } + + std::vector& ypB() override + { + return ypB_; + } + + const std::vector& ypB() const override + { + return ypB_; + } + + std::vector& param() override + { + return param_; + } + + const std::vector& param() const override + { + return param_; + } + + std::vector& param_up() override + { + return param_up_; + } + + const std::vector& param_up() const override + { + return param_up_; + } + + std::vector& param_lo() override + { + return param_lo_; + } + + const std::vector& param_lo() const override + { + return param_lo_; + } + + std::vector& getResidual() override + { + return residual_; + } + + const std::vector& getResidual() const override + { + return residual_; + } + + MatrixT& getJacobian() override + { + return jacobian_; + } + + const MatrixT& getJacobian() const override + { + return jacobian_; + } + + std::vector& getIntegrand() override + { + return integrand_; + } + + const std::vector& getIntegrand() const override + { + return integrand_; + } + + std::vector& getAdjointResidual() override + { + return adj_residual_; + } + + const std::vector& getAdjointResidual() const override + { + return adj_residual_; + } + + std::vector& getAdjointIntegrand() override + { + return adj_integrand_; + } + + const std::vector& getAdjointIntegrand() const override + { + return adj_integrand_; + } + + void addForcing(const ForcingFunc& f) + { + forcing_.push_back(f); + } + + IdxT getCouplingSize() const + { + return static_cast(coupling_.size()); + } + + IdxT getStateSize() const + { + return static_cast(y_.size()); + } + + std::vector& getCoupling() + { + return coupling_; + } + + const std::vector& getCoupling() const + { + return coupling_; + } + }; + + } // namespace Model +} // namespace GridKit \ No newline at end of file diff --git a/GridKit/Solver/Dynamic/MultiStageCosimulation.cpp b/GridKit/Solver/Dynamic/MultiStageCosimulation.cpp new file mode 100644 index 000000000..390eb8d03 --- /dev/null +++ b/GridKit/Solver/Dynamic/MultiStageCosimulation.cpp @@ -0,0 +1,124 @@ + +#include "MultiStageCosimulation.hpp"; + +#include + +#include +#include +#include + +namespace Integrator +{ + + // TODO: Complete implementation + template + int MultiStageCosimulation::allocate() + { + + for (size_t p = 0; p < num_partitions_; ++p) + { + auto* part = partitions_[p]; + + int num_coupling = part->getCouplingSize(); + int num_states = part->getStateSize(); + + x0_local_[p] = State(num_states); + coupling_mat_[p] = State(num_coupling, num_stages_); + + x0_local_[p].allocate(memspace_); + coupling_mat_[p].allocate(memspace_); + } + + return 0; + } + + template + int MultiStageCosimulation::distributeLocal(const State& global_y) + { + + auto* global_data = global_y.getData(memspace_); + + for (size_t p = 0; p < num_partitions_; ++p) + { + auto* part = partitions_[p]; + auto& internal = part->getInternalIndecies(); // TODO: add this function to partition evaluate + size_t n = part->size(); + + auto* local_data = x0_local_[p].getData(memspace_); + + for (size_t i = 0; i < n; ++i) + { + local_data[i] = global_data[internal[i]]; + } + } + + return 0; + } + + template + int MultiStageCosimulation::distributeCoupling(const State& global_y, int stage) + { + + auto* global_data = global_y.getData(memspace_); + + for (size_t p = 0; p < num_partitions_; ++p) + { + auto* part = partitions_[p]; + auto& external = part->getExternalIndices(); // TODO: add this function to partition evaluate + size_t n = part->size(); + + auto* local_data = coupling_mat_[p].getData(stage, memspace_); + + for (size_t i = 0; i < n; ++i) + { + local_data[i] = global_data[external[i]]; + } + } + + return 0; + } + + // TODO: Complete implementation + template + int MultiStageCosimulation::timestep(const State& global_y) + { + return 0; + } + + // TODO: Complete implementation + template + int MultiStageCosimulation::partitionSolve() + { + + std::vector output_time = output_times; + + for (size_t i = 0; i < max_iterations_; i++) + { + for (auto* partitionEvaluator : partitions_) + { + + // TODO: add a coupling function to the partition + partitionEvaluator->addForcing(); + + if (i + 1 < max_iterations_) + { + solver.integrate({t0}, partition_solution_.getData(stage)); + } + else + { + solver.integrate(output_time, partition_solution_); + } + } + + updateCoupling(stage + 1) + + if (stage == 0) + { + break; + } + } + + return 0; + } + +} // namespace Integrator \ No newline at end of file diff --git a/GridKit/Solver/Dynamic/MultiStageCosimulation.hpp b/GridKit/Solver/Dynamic/MultiStageCosimulation.hpp new file mode 100644 index 000000000..ddc3ceb6a --- /dev/null +++ b/GridKit/Solver/Dynamic/MultiStageCosimulation.hpp @@ -0,0 +1,133 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace Integrator +{ + + template + class MultiStageCosimulation + { + using State = ReSolve::vector::Vector; + using RealT = typename GridKit::ScalarTraits::RealT; + using Rosenbrock = Integrator::Rosenbrock; + using PartitionEvaluator = GridKit::Model::PartitionEvaluator; + + public: + int initializeSimulation(RealT t0); + + int runSimulation(RealT tn, IdxT nout, std::optional> step_callback = {}); + + int partitionSolve(); + + int timestepper(const std::vector& out_times, + std::optional> out_cb = {}); + + int distributeLocal(const State& global_y); + + int distributeCoupling(const State& global_y, int stage); + + int allocate(); + + private: + /** + * @brief initial time + */ + RealT t0_; + /** + * @brief Maximum number of iterations per stage + */ + size_t max_iterations_; + + /** + * + * @brief Number of partitions in the problem + */ + size_t num_partitions_; + + /** + * + * @brief Number of stages used by the method + */ + size_t num_stages_; + + /** + * + * @brief Memory space used + */ + ReSolve::memory::MemorySpace memspace_; + + /** + * + * @brief Handles for linear algebra operations + * + */ + ReSolve::VectorHandler vector_handler_; + + /** + * + * @brief linear solver for the sub-integrator + * + */ + std::vector> lin_solver_; + + /** + * + * @brief Contains vectors of initial conditions for every step + * + */ + std::vector x0_local_; + + /** + * + * @brief Vectors of coupling matrices for each partition + * + */ + std::vector coupling_mat_; + + /** + * + * @brief Vector of stages + * + */ + State stages_; + + /** + * + * @brief partition solution multi-dimensional vectors + * + */ + State partition_solution_; + + /** + * + *@brief Vector of partitions + */ + std::vector partitions_; + + /** + * + *@brief Vector of solvers + */ + std::vector> solvers_; + }; +} // namespace Integrator From 60a34ac4659817b1a8737bd1e095335b8b930f7e Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Mon, 1 Jun 2026 15:28:33 +0000 Subject: [PATCH 02/34] Added partition interfaces to power electronics and updated cmake files. During partitioning: - BusPartitionInterface connects to the bus partition - ComponentPartitionInterface connects to the component partition --- GridKit/Model/PowerElectronics/CMakeLists.txt | 1 + .../BusPartitionInterface.cpp | 182 ++++++++++++++++++ .../BusPartitionInterface.hpp | 70 +++++++ .../PartitionInterface/CMakeLists.txt | 8 + .../ComponentPartitionInterface.cpp | 176 +++++++++++++++++ .../ComponentPartitionInterface.hpp | 75 ++++++++ .../PartitionInterface/PartitionInterface.hpp | 74 +++++++ examples/PowerElectronics/CMakeLists.txt | 1 + .../PowerElectronics/Partition/CMakeLists.txt | 4 + .../PowerElectronics/Partition/HiresBus.hpp | 104 ++++++++++ .../Partition/HiresComponent1.hpp | 109 +++++++++++ .../Partition/HiresComponent2.hpp | 109 +++++++++++ .../PowerElectronics/Partition/Partition.cpp | 114 +++++++++++ 13 files changed, 1027 insertions(+) create mode 100644 GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp create mode 100644 GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp create mode 100644 GridKit/Model/PowerElectronics/PartitionInterface/CMakeLists.txt create mode 100644 GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.cpp create mode 100644 GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.hpp create mode 100644 GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp create mode 100644 examples/PowerElectronics/Partition/CMakeLists.txt create mode 100644 examples/PowerElectronics/Partition/HiresBus.hpp create mode 100644 examples/PowerElectronics/Partition/HiresComponent1.hpp create mode 100644 examples/PowerElectronics/Partition/HiresComponent2.hpp create mode 100644 examples/PowerElectronics/Partition/Partition.cpp diff --git a/GridKit/Model/PowerElectronics/CMakeLists.txt b/GridKit/Model/PowerElectronics/CMakeLists.txt index 98dce1148..bdedb72e3 100644 --- a/GridKit/Model/PowerElectronics/CMakeLists.txt +++ b/GridKit/Model/PowerElectronics/CMakeLists.txt @@ -21,6 +21,7 @@ add_subdirectory(TransmissionLine) add_subdirectory(MicrogridLoad) add_subdirectory(MicrogridLine) add_subdirectory(MicrogridBusDQ) +add_subdirectory(PartitionInterface) install( FILES CircuitComponent.hpp diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp new file mode 100644 index 000000000..9b1e47e40 --- /dev/null +++ b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp @@ -0,0 +1,182 @@ + +#include "BusPartitionInterface.hpp" + +#include +#include +#include + +namespace GridKit +{ + + /*! + * @brief Construct a bus-level partition interface. + * + * This interface exposes only the two bus variables associated with a + * component that has been separated from the rest of the system during + * partitioning. Internally, it maintains a copy of the original component + * and acts as a proxy between the co-simulation algorithm and the component + * model. + * + * The bus variables become the internal variables of this interface, + * while all remaining component variables are treated as external data + * supplied by neighboring partitions. + * + * @param component Circuit component associated with this interface. + * @param id Unique component identifier. + */ + template + BusPartitionInterface::BusPartitionInterface(CircuitComponent& component, IdxT id) + : component_(component) + { + size_ = 2; + n_intern_ = 0; + n_extern_ = 2; + extern_indices_ = {0, 1}; + idc_ = id; + } + + template + BusPartitionInterface::~BusPartitionInterface() + { + } + + /*! + * @brief allocate method computes sparsity pattern of the Jacobian. + */ + template + int BusPartitionInterface::allocate() + { + y_.resize(static_cast(size_)); + yp_.resize(static_cast(size_)); + f_.resize(static_cast(size_)); + + size_t interface_extern_size = static_cast(component_.size() - size_); + interface_partition_externals_.resize(interface_extern_size); + external_data_y_.resize(interface_extern_size, 0); + external_data_yp_.resize(interface_extern_size, 0); + + component_.allocate(); + + auto bus_i = this->getNodeConnection(0); + auto bus_j = this->getNodeConnection(1); + + size_t counter = 0; + for (size_t i = 0; i < static_cast(component_.size()); i++) + { + if (bus_i == component_.getNodeConnection(static_cast(i))) + { + bus_port_i_ = i; + } + else if (bus_j == component_.getNodeConnection(static_cast(i))) + { + bus_port_j_ = i; + } + else + { + interface_partition_externals_[counter] = component_.getNodeConnection(static_cast(i)); + counter++; + } + } + + return 0; + } + + /** + * Initialization of the grid model + */ + template + int BusPartitionInterface::initialize() + { + return 0; + } + + /* + * \brief Identify differential variables + */ + template + int BusPartitionInterface::tagDifferentiable() + { + return 0; + } + + /** + * @brief Eval Micro Load + */ + template + int BusPartitionInterface::evaluateResidual() + { + auto& y = component_.y(); + auto& yp = component_.yp(); + + y[bus_port_i_] = y_[0]; + y[bus_port_j_] = y_[1]; + + yp[bus_port_i_] = yp_[0]; + yp[bus_port_j_] = yp_[1]; + + size_t counter = 0; + for (size_t i = 0; i < static_cast(component_.size()); i++) + { + if (bus_port_i_ != i && bus_port_j_ != i) + { + y[i] = external_data_y_[counter]; + counter++; + } + } + + component_.evaluateResidual(); + + auto& f = component_.getResidual(); + + f_[0] = f[bus_port_i_]; + f_[1] = f[bus_port_j_]; + + return 0; + } + + /** + * @brief Generate Jacobian for Micro Load + * + * @tparam ScalarT + * @tparam IdxT + * @return int + */ + template + int BusPartitionInterface::evaluateJacobian() + { + jac_.zeroMatrix(); + + return 0; + } + + template + int BusPartitionInterface::evaluateIntegrand() + { + return 0; + } + + template + int BusPartitionInterface::initializeAdjoint() + { + return 0; + } + + template + int BusPartitionInterface::evaluateAdjointResidual() + { + return 0; + } + + template + int BusPartitionInterface::evaluateAdjointIntegrand() + { + return 0; + } + + // Available template instantiations + template class BusPartitionInterface; + template class BusPartitionInterface; + template class BusPartitionInterface; + template class BusPartitionInterface; + +} // namespace GridKit diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp new file mode 100644 index 000000000..7e4fbef6c --- /dev/null +++ b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp @@ -0,0 +1,70 @@ + + +#pragma once + +#include + +#include + +#include "GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp" + +namespace GridKit +{ + /*! + * @brief Declaration of a passive BusPartitionInterface class. + * + */ + template + class BusPartitionInterface : public PartitionInterface + { + using RealT = typename CircuitComponent::RealT; + using MatrixT = typename CircuitComponent::MatrixT; + + using PartitionInterface::external_data_y_; + using PartitionInterface::external_data_yp_; + using PartitionInterface::interface_partition_externals_; + + using CircuitComponent::size_; + using CircuitComponent::nnz_; + using CircuitComponent::time_; + using CircuitComponent::alpha_; + using CircuitComponent::y_; + using CircuitComponent::yp_; + using CircuitComponent::tag_; + using CircuitComponent::f_; + using CircuitComponent::g_; + using CircuitComponent::yB_; + using CircuitComponent::ypB_; + using CircuitComponent::fB_; + using CircuitComponent::gB_; + using CircuitComponent::jac_; + using CircuitComponent::param_; + using CircuitComponent::idc_; + + using CircuitComponent::extern_indices_; + using CircuitComponent::n_extern_; + using CircuitComponent::n_intern_; + + public: + BusPartitionInterface(CircuitComponent& component, IdxT id); + virtual ~BusPartitionInterface(); + + int allocate(); + int initialize(); + int tagDifferentiable(); + int evaluateResidual(); + int evaluateJacobian(); + int evaluateIntegrand(); + + int initializeAdjoint(); + int evaluateAdjointResidual(); + // int evaluateAdjointJacobian(); + int evaluateAdjointIntegrand(); + + private: + size_t bus_port_i_; + size_t bus_port_j_; + + CircuitComponent& component_; + }; +} // namespace GridKit diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/CMakeLists.txt b/GridKit/Model/PowerElectronics/PartitionInterface/CMakeLists.txt new file mode 100644 index 000000000..28fb804b0 --- /dev/null +++ b/GridKit/Model/PowerElectronics/PartitionInterface/CMakeLists.txt @@ -0,0 +1,8 @@ +gridkit_add_library(power_elec_partition_interfaces + SOURCES + BusPartitionInterface.cpp + ComponentPartitionInterface.cpp + HEADERS + BusPartitionInterface.hpp + ComponentPartitionInterface.hpp + PartitionInterface.hpp) diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.cpp b/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.cpp new file mode 100644 index 000000000..bc33b102f --- /dev/null +++ b/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.cpp @@ -0,0 +1,176 @@ + + +#include "ComponentPartitionInterface.hpp" + +#include +#include +#include +#include + +namespace GridKit +{ + + /*! + * @brief Constructor for a constant MicrogridLoad model + * + * Calls default ModelEvaluatorImpl constructor. + * + * + * + */ + + template + ComponentPartitionInterface::ComponentPartitionInterface(CircuitComponent* component, IdxT bus_i, IdxT bus_j, IdxT id) + : component_(component), + bus_i_(bus_i), + bus_j_(bus_j) + { + // internals [id, iq] + // externals [\omegaref, vbd_out, vbq_out] + size_ = component_->size(); + n_intern_ = component_->getInternalSize(); + n_extern_ = component_->getExternSize(); + extern_indices_ = component_->getExternIndices(); + idc_ = id; + } + + template + ComponentPartitionInterface::~ComponentPartitionInterface() + { + } + + /*! + * @brief allocate method computes sparsity pattern of the Jacobian. + */ + template + int ComponentPartitionInterface::allocate() + { + + size_t bus_size = 2; + + y_.resize(static_cast(size_)); + yp_.resize(static_cast(size_)); + f_.resize(static_cast(size_)); + interface_partition_externals_.resize(bus_size); + external_data_y_.resize(bus_size, 0); + external_data_yp_.resize(bus_size, 0); + + component_->allocate(); + + for (size_t i = 0; i < static_cast(size_); i++) + { + auto index = component_->getNodeConnection(static_cast(i)); + if (bus_i_ == index) + { + bus_port_i_ = i; + } + else if (bus_j_ == index) + { + bus_port_j_ = i; + } + else + { + this->setExternalConnectionNodes(static_cast(i), index); + } + } + + this->setExternalConnectionNodes(static_cast(bus_port_i_), static_cast(-1)); + this->setExternalConnectionNodes(static_cast(bus_port_j_), static_cast(-1)); + + interface_partition_externals_[0] = bus_i_; + interface_partition_externals_[1] = bus_j_; + + return 0; + } + + /** + * Initialization of the grid model + */ + template + int ComponentPartitionInterface::initialize() + { + return 0; + } + + /* + * \brief Identify differential variables + */ + template + int ComponentPartitionInterface::tagDifferentiable() + { + return 0; + } + + /** + * @brief Eval Micro Load + */ + template + int ComponentPartitionInterface::evaluateResidual() + { + + auto& y = component_->y(); + auto& yp = component_->yp(); + + std::copy(y_.begin(), y_.end(), y.begin()); + std::copy(yp_.begin(), yp_.end(), yp.begin()); + + y[bus_port_i_] = external_data_y_[0]; + y[bus_port_j_] = external_data_y_[1]; + + yp[bus_port_i_] = external_data_yp_[0]; + yp[bus_port_j_] = external_data_yp_[1]; + + component_->evaluateResidual(); + auto& f = component_->getResidual(); + + std::copy(f.begin(), f.end(), f_.begin()); + + return 0; + } + + /** + * @brief Generate Jacobian for Micro Load + * + * @tparam ScalarT + * @tparam IdxT + * @return int + */ + template + int ComponentPartitionInterface::evaluateJacobian() + { + jac_.zeroMatrix(); + + return 0; + } + + template + int ComponentPartitionInterface::evaluateIntegrand() + { + return 0; + } + + template + int ComponentPartitionInterface::initializeAdjoint() + { + return 0; + } + + template + int ComponentPartitionInterface::evaluateAdjointResidual() + { + return 0; + } + + template + int ComponentPartitionInterface::evaluateAdjointIntegrand() + { + return 0; + } + + // Available template instantiations + template class ComponentPartitionInterface; + template class ComponentPartitionInterface; + template class ComponentPartitionInterface; + template class ComponentPartitionInterface; + +} // namespace GridKit diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.hpp b/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.hpp new file mode 100644 index 000000000..d7d1b3926 --- /dev/null +++ b/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include + +#include + +#include "GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp" + +namespace GridKit +{ + template + class BaseBus; +} + +namespace GridKit +{ + /*! + * @brief Declaration of a passive ComponentPartitionInterface class. + * + */ + template + class ComponentPartitionInterface : public PartitionInterface + { + using RealT = typename CircuitComponent::RealT; + using MatrixT = typename CircuitComponent::MatrixT; + + using PartitionInterface::external_data_y_; + using PartitionInterface::external_data_yp_; + using PartitionInterface::interface_partition_externals_; + + using CircuitComponent::size_; + using CircuitComponent::nnz_; + using CircuitComponent::time_; + using CircuitComponent::alpha_; + using CircuitComponent::y_; + using CircuitComponent::yp_; + using CircuitComponent::tag_; + using CircuitComponent::f_; + using CircuitComponent::g_; + using CircuitComponent::yB_; + using CircuitComponent::ypB_; + using CircuitComponent::fB_; + using CircuitComponent::gB_; + using CircuitComponent::jac_; + using CircuitComponent::param_; + using CircuitComponent::idc_; + using CircuitComponent::extern_indices_; + using CircuitComponent::n_extern_; + using CircuitComponent::n_intern_; + + public: + ComponentPartitionInterface(CircuitComponent* component, IdxT bus_i, IdxT bus_j, IdxT id); + virtual ~ComponentPartitionInterface(); + + int allocate(); + int initialize(); + int tagDifferentiable(); + int evaluateResidual(); + int evaluateJacobian(); + int evaluateIntegrand(); + + int initializeAdjoint(); + int evaluateAdjointResidual(); + // int evaluateAdjointJacobian(); + int evaluateAdjointIntegrand(); + + private: + CircuitComponent* component_; + + size_t bus_port_i_; + size_t bus_port_j_; + IdxT bus_i_; + IdxT bus_j_; + }; +} // namespace GridKit diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp b/GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp new file mode 100644 index 000000000..96202da2e --- /dev/null +++ b/GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp @@ -0,0 +1,74 @@ + + +#pragma once + +#include +#include + +#include +#include +#include + +namespace GridKit +{ + /*! + * @brief Base class for partition interface components. + * + * PartitionInterface provides the infrastructure needed by components + * that exchange information across partition boundaries during + * co-simulation. It stores the values of external variables received + * from neighboring partitions together with the corresponding global + * indices in the original unpartitioned system. + * + * Derived classes are responsible for implementing the specific + * interface behavior associated with buses, circuit components, or + * other partition boundary entities. + */ + template + class PartitionInterface : public CircuitComponent + { + public: + using RealT = typename Model::Evaluator::RealT; + using MatrixT = typename Model::Evaluator::MatrixT; + using CsrMatrixT = typename Model::Evaluator::CsrMatrixT; + + PartitionInterface() = default; + + ~PartitionInterface() = default; + + int setExternalDataY(const std::vector& data) + { + std::copy(data.begin(), data.end(), external_data_y_.begin()); + + return 0; + } + + int setExternalDataYP(const std::vector& data) + { + std::copy(data.begin(), data.end(), external_data_yp_.begin()); + + return 0; + } + + std::vector& getExternalDataY() + { + return external_data_y_; + } + + std::vector& getExternalDataYP() + { + return external_data_yp_; + } + + std::vector& getPartitionExternalIndices() + { + return interface_partition_externals_; + } + + protected: + std::vector external_data_y_; + std::vector external_data_yp_; + std::vector interface_partition_externals_; + }; + +} // namespace GridKit diff --git a/examples/PowerElectronics/CMakeLists.txt b/examples/PowerElectronics/CMakeLists.txt index 2bf311e22..bdf85eb07 100644 --- a/examples/PowerElectronics/CMakeLists.txt +++ b/examples/PowerElectronics/CMakeLists.txt @@ -10,5 +10,6 @@ if(TARGET SUNDIALS::idas) add_subdirectory(RLCircuit) add_subdirectory(Microgrid) add_subdirectory(ScaleMicrogrid) + add_subdirectory(Partition) endif() endif() diff --git a/examples/PowerElectronics/Partition/CMakeLists.txt b/examples/PowerElectronics/Partition/CMakeLists.txt new file mode 100644 index 000000000..a5d192a9d --- /dev/null +++ b/examples/PowerElectronics/Partition/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(partition Partition.cpp) +target_link_libraries(partition GridKit::solvers_dyn + GridKit::power_elec_partition_interfaces) + diff --git a/examples/PowerElectronics/Partition/HiresBus.hpp b/examples/PowerElectronics/Partition/HiresBus.hpp new file mode 100644 index 000000000..a01152ac0 --- /dev/null +++ b/examples/PowerElectronics/Partition/HiresBus.hpp @@ -0,0 +1,104 @@ +#pragma once + +#include + +namespace GridKit +{ + /*! + * @brief Declaration of a MicrogridLine class. + * + */ + template + class HiresBus : public CircuitComponent + { + using RealT = typename CircuitComponent::RealT; + using MatrixT = typename CircuitComponent::MatrixT; + + using CircuitComponent::size_; + using CircuitComponent::nnz_; + using CircuitComponent::time_; + using CircuitComponent::alpha_; + using CircuitComponent::y_; + using CircuitComponent::yp_; + using CircuitComponent::tag_; + using CircuitComponent::f_; + using CircuitComponent::g_; + using CircuitComponent::yB_; + using CircuitComponent::ypB_; + using CircuitComponent::fB_; + using CircuitComponent::gB_; + using CircuitComponent::jac_; + using CircuitComponent::param_; + using CircuitComponent::idc_; + + using CircuitComponent::extern_indices_; + using CircuitComponent::n_extern_; + using CircuitComponent::n_intern_; + + public: + HiresBus(IdxT id) + { + size_ = 2; + n_intern_ = 2; + n_extern_ = 0; + extern_indices_ = {}; + idc_ = id; + } + + ~HiresBus() + { + } + + int allocate() + { + y_.resize(static_cast(size_)); + yp_.resize(static_cast(size_)); + f_.resize(static_cast(size_)); + + return 0; + } + + int initialize() + { + return 0; + } + + int tagDifferentiable() + { + return 0; + } + + int evaluateResidual() + { + f_[0] = -y_[0]; + f_[1] = -y_[1]; + + return 0; + } + + int evaluateJacobian() + { + return 0; + } + + int evaluateIntegrand() + { + return 0; + } + + int initializeAdjoint() + { + return 0; + } + + int evaluateAdjointResidual() + { + return 0; + } + + int evaluateAdjointIntegrand() + { + return 0; + } + }; +} // namespace GridKit \ No newline at end of file diff --git a/examples/PowerElectronics/Partition/HiresComponent1.hpp b/examples/PowerElectronics/Partition/HiresComponent1.hpp new file mode 100644 index 000000000..7314264b0 --- /dev/null +++ b/examples/PowerElectronics/Partition/HiresComponent1.hpp @@ -0,0 +1,109 @@ + + +#pragma once + +#include + +namespace GridKit +{ + /*! + * @brief Declaration of a HiresComponent1 class. + * + */ + template + class HiresComponent1 : public CircuitComponent + { + using RealT = typename CircuitComponent::RealT; + using MatrixT = typename CircuitComponent::MatrixT; + + using CircuitComponent::size_; + using CircuitComponent::nnz_; + using CircuitComponent::time_; + using CircuitComponent::alpha_; + using CircuitComponent::y_; + using CircuitComponent::yp_; + using CircuitComponent::tag_; + using CircuitComponent::f_; + using CircuitComponent::g_; + using CircuitComponent::yB_; + using CircuitComponent::ypB_; + using CircuitComponent::fB_; + using CircuitComponent::gB_; + using CircuitComponent::jac_; + using CircuitComponent::param_; + using CircuitComponent::idc_; + + using CircuitComponent::extern_indices_; + using CircuitComponent::n_extern_; + using CircuitComponent::n_intern_; + + public: + HiresComponent1(IdxT id) + { + size_ = 5; + n_intern_ = 3; + n_extern_ = 2; + extern_indices_ = {3, 4}; + idc_ = id; + } + + ~HiresComponent1() + { + } + + int allocate() + { + y_.resize(static_cast(size_)); + yp_.resize(static_cast(size_)); + f_.resize(static_cast(size_)); + + return 0; + } + + int initialize() + { + return 0; + } + + int tagDifferentiable() + { + return 0; + } + + int evaluateResidual() + { + f_[0] = -1.71 * y_[0] + 0.43 * y_[1] + 8.32 * y_[2] + 0.0007; + f_[1] = 1.71 * y_[0] - 8.75 * y_[1]; + f_[2] = -10.03 * y_[2] + 0.43 * y_[3] + 0.035 * y_[4]; + f_[3] = 8.32 * y_[1] + 1.71 * y_[2] - 0.1 * y_[3]; + f_[4] = -0.7 * y_[4]; + + return 0; + } + + int evaluateJacobian() + { + return 0; + } + + int evaluateIntegrand() + { + return 0; + } + + int initializeAdjoint() + { + return 0; + } + + int evaluateAdjointResidual() + { + return 0; + } + + int evaluateAdjointIntegrand() + { + return 0; + } + }; +} // namespace GridKit diff --git a/examples/PowerElectronics/Partition/HiresComponent2.hpp b/examples/PowerElectronics/Partition/HiresComponent2.hpp new file mode 100644 index 000000000..c1787e51a --- /dev/null +++ b/examples/PowerElectronics/Partition/HiresComponent2.hpp @@ -0,0 +1,109 @@ + + +#pragma once + +#include + +namespace GridKit +{ + /*! + * @brief Declaration of a HiresComponent1 class. + * + */ + template + class HiresComponent2 : public CircuitComponent + { + using RealT = typename CircuitComponent::RealT; + using MatrixT = typename CircuitComponent::MatrixT; + + using CircuitComponent::size_; + using CircuitComponent::nnz_; + using CircuitComponent::time_; + using CircuitComponent::alpha_; + using CircuitComponent::y_; + using CircuitComponent::yp_; + using CircuitComponent::tag_; + using CircuitComponent::f_; + using CircuitComponent::g_; + using CircuitComponent::yB_; + using CircuitComponent::ypB_; + using CircuitComponent::fB_; + using CircuitComponent::gB_; + using CircuitComponent::jac_; + using CircuitComponent::param_; + using CircuitComponent::idc_; + + using CircuitComponent::extern_indices_; + using CircuitComponent::n_extern_; + using CircuitComponent::n_intern_; + + public: + HiresComponent2(IdxT id) + { + size_ = 5; + n_intern_ = 3; + n_extern_ = 2; + extern_indices_ = {3, 4}; + idc_ = id; + } + + ~HiresComponent2() + { + } + + int allocate() + { + y_.resize(static_cast(size_)); + yp_.resize(static_cast(size_)); + f_.resize(static_cast(size_)); + + return 0; + } + + int initialize() + { + return 0; + } + + int tagDifferentiable() + { + return 0; + } + + int evaluateResidual() + { + f_[0] = -280 * y_[0] * y_[2] + 0.69 * y_[3] + 1.71 * y_[4] - 0.43 * y_[0] + 0.69 * y_[1]; + f_[1] = 280 * y_[0] * y_[2] - 1.81 * y_[1]; + f_[2] = -280 * y_[0] * y_[2] + 1.81 * y_[1]; + f_[3] = -0.02 * y_[3]; + f_[4] = -0.045 * y_[4] + 0.43 * y_[0] + 0.43 * y_[1]; + + return 0; + } + + int evaluateJacobian() + { + return 0; + } + + int evaluateIntegrand() + { + return 0; + } + + int initializeAdjoint() + { + return 0; + } + + int evaluateAdjointResidual() + { + return 0; + } + + int evaluateAdjointIntegrand() + { + return 0; + } + }; +} // namespace GridKit diff --git a/examples/PowerElectronics/Partition/Partition.cpp b/examples/PowerElectronics/Partition/Partition.cpp new file mode 100644 index 000000000..67afcd264 --- /dev/null +++ b/examples/PowerElectronics/Partition/Partition.cpp @@ -0,0 +1,114 @@ +#include + +#define _USE_MATH_DEFINES +#include +#include +#include + +#include +#include +#include + +#include "HiresBus.hpp" +#include "HiresComponent1.hpp" +#include "HiresComponent2.hpp" + +std::vector hires(std::vector y); + +int main(int /* argc */, char const** /* argv */) +{ + + double abs_tol = 1.0e-5; + double rel_tol = 1.0e-5; + size_t max_step_number = 3000; + bool use_jac = true; + + auto* partition1 = new GridKit::PowerElectronicsModel(rel_tol, abs_tol, use_jac, max_step_number); + auto* partition2 = new GridKit::PowerElectronicsModel(rel_tol, abs_tol, use_jac, max_step_number); + + GridKit::HiresComponent1* comp1 = new GridKit::HiresComponent1(1); + GridKit::HiresBus* bus1 = new GridKit::HiresBus(2); + GridKit::HiresComponent2* comp2 = new GridKit::HiresComponent2(3); + + comp1->setExternalConnectionNodes(0, 0); + comp1->setExternalConnectionNodes(1, 1); + comp1->setExternalConnectionNodes(2, 2); + comp1->setExternalConnectionNodes(3, 3); + comp1->setExternalConnectionNodes(4, 4); + + bus1->setExternalConnectionNodes(0, 3); + bus1->setExternalConnectionNodes(1, 4); + + comp2->setExternalConnectionNodes(0, 5); + comp2->setExternalConnectionNodes(1, 6); + comp2->setExternalConnectionNodes(2, 7); + comp2->setExternalConnectionNodes(3, 3); + comp2->setExternalConnectionNodes(4, 4); + + GridKit::HiresComponent2 comp2copy(*comp2); + GridKit::BusPartitionInterface* busInterface = new GridKit::BusPartitionInterface(comp2copy, 10); + GridKit::ComponentPartitionInterface* compInterface = new GridKit::ComponentPartitionInterface(comp2, 3, 4, 9); + + busInterface->setExternalConnectionNodes(0, 3); + busInterface->setExternalConnectionNodes(1, 4); + + partition1->addComponent(comp1); + partition1->addComponent(bus1); + partition1->addComponent(busInterface); + + partition2->addComponent(compInterface); + + size_t sys_size = 8; + + partition1->allocate(sys_size); + partition2->allocate(sys_size); + + busInterface->setExternalDataY({6, 7, 8}); + compInterface->setExternalDataY({4, 5}); + + for (size_t i = 0; i < sys_size; i++) + { + + partition1->y()[i] = static_cast(i) + 1; + partition1->yp()[i] = static_cast(i) + 1; + + partition2->y()[i] = static_cast(i) + 1; + partition2->yp()[i] = static_cast(i) + 1; + } + + partition1->evaluateResidual(); + partition2->evaluateResidual(); + + auto ref = hires({1, 2, 3, 4, 5, 6, 7, 8}); + + std::cout << "------------- Partition 1 -----------" << std::endl; + for (size_t i = 0; i < sys_size; i++) + { + printf("%-10.5g ---------- %10.5g\n", partition1->getResidual()[i], ref[i]); + } + + std::cout << "\n------------- Partition 2 -----------" << std::endl; + for (size_t i = 0; i < sys_size; i++) + { + printf("%-10.5g ---------- %10.5g\n", partition2->getResidual()[i], ref[i]); + } + + delete partition1; + delete partition2; +} + +std::vector hires(std::vector y) +{ + std::vector f(8); + + f[0] = -1.71 * y[0] + 0.43 * y[1] + 8.32 * y[2] + 0.0007; + f[1] = 1.71 * y[0] - 8.75 * y[1]; + f[2] = -10.03 * y[2] + 0.43 * y[3] + 0.035 * y[4]; + f[3] = 8.32 * y[1] + 1.71 * y[2] - 1.12 * y[3]; + f[4] = -1.745 * y[4] + 0.43 * y[5] + 0.43 * y[6]; + f[5] = -280 * y[5] * y[7] + 0.69 * y[3] + 1.71 * y[4] - 0.43 * y[5] + 0.69 * y[6]; + f[6] = 280 * y[5] * y[7] - 1.81 * y[6]; + f[7] = -280 * y[5] * y[7] + 1.81 * y[6]; + + return f; +} From 8004577fceca9489c66f5c1ce95db51f25959b80 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Wed, 3 Jun 2026 05:24:24 +0000 Subject: [PATCH 03/34] Made minor changes to partition interface code --- .../PartitionInterface/BusPartitionInterface.cpp | 15 +++++++++------ .../PartitionInterface/BusPartitionInterface.hpp | 9 +++++---- .../ComponentPartitionInterface.cpp | 7 ++++--- .../ComponentPartitionInterface.hpp | 9 ++++----- .../PartitionInterface/PartitionInterface.hpp | 5 +++++ 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp index 9b1e47e40..b2c806b26 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp @@ -25,7 +25,7 @@ namespace GridKit * @param id Unique component identifier. */ template - BusPartitionInterface::BusPartitionInterface(CircuitComponent& component, IdxT id) + BusPartitionInterface::BusPartitionInterface(CircuitComponent& component, IdxT bus_i, IdxT bus_j, IdxT id) : component_(component) { size_ = 2; @@ -33,6 +33,9 @@ namespace GridKit n_extern_ = 2; extern_indices_ = {0, 1}; idc_ = id; + + bus_i_ = bus_i; + bus_j_ = bus_j; } template @@ -57,17 +60,14 @@ namespace GridKit component_.allocate(); - auto bus_i = this->getNodeConnection(0); - auto bus_j = this->getNodeConnection(1); - size_t counter = 0; for (size_t i = 0; i < static_cast(component_.size()); i++) { - if (bus_i == component_.getNodeConnection(static_cast(i))) + if (bus_i_ == component_.getNodeConnection(static_cast(i))) { bus_port_i_ = i; } - else if (bus_j == component_.getNodeConnection(static_cast(i))) + else if (bus_j_ == component_.getNodeConnection(static_cast(i))) { bus_port_j_ = i; } @@ -78,6 +78,9 @@ namespace GridKit } } + this->setExternalConnectionNodes(0, bus_i_); + this->setExternalConnectionNodes(1, bus_j_); + return 0; } diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp index 7e4fbef6c..1b1d9e4bd 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp @@ -23,6 +23,10 @@ namespace GridKit using PartitionInterface::external_data_y_; using PartitionInterface::external_data_yp_; using PartitionInterface::interface_partition_externals_; + using PartitionInterface::bus_port_i_; + using PartitionInterface::bus_port_j_; + using PartitionInterface::bus_i_; + using PartitionInterface::bus_j_; using CircuitComponent::size_; using CircuitComponent::nnz_; @@ -46,7 +50,7 @@ namespace GridKit using CircuitComponent::n_intern_; public: - BusPartitionInterface(CircuitComponent& component, IdxT id); + BusPartitionInterface(CircuitComponent& component, IdxT bus_i, IdxT bus_j, IdxT id); virtual ~BusPartitionInterface(); int allocate(); @@ -62,9 +66,6 @@ namespace GridKit int evaluateAdjointIntegrand(); private: - size_t bus_port_i_; - size_t bus_port_j_; - CircuitComponent& component_; }; } // namespace GridKit diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.cpp b/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.cpp index bc33b102f..3c88c4dee 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.cpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.cpp @@ -21,9 +21,7 @@ namespace GridKit template ComponentPartitionInterface::ComponentPartitionInterface(CircuitComponent* component, IdxT bus_i, IdxT bus_j, IdxT id) - : component_(component), - bus_i_(bus_i), - bus_j_(bus_j) + : component_(component) { // internals [id, iq] // externals [\omegaref, vbd_out, vbq_out] @@ -32,6 +30,9 @@ namespace GridKit n_extern_ = component_->getExternSize(); extern_indices_ = component_->getExternIndices(); idc_ = id; + + bus_i_ = bus_i; + bus_j_ = bus_j; } template diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.hpp b/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.hpp index d7d1b3926..a46231f6d 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.hpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.hpp @@ -27,6 +27,10 @@ namespace GridKit using PartitionInterface::external_data_y_; using PartitionInterface::external_data_yp_; using PartitionInterface::interface_partition_externals_; + using PartitionInterface::bus_port_i_; + using PartitionInterface::bus_port_j_; + using PartitionInterface::bus_i_; + using PartitionInterface::bus_j_; using CircuitComponent::size_; using CircuitComponent::nnz_; @@ -66,10 +70,5 @@ namespace GridKit private: CircuitComponent* component_; - - size_t bus_port_i_; - size_t bus_port_j_; - IdxT bus_i_; - IdxT bus_j_; }; } // namespace GridKit diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp b/GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp index 96202da2e..85599404c 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp @@ -69,6 +69,11 @@ namespace GridKit std::vector external_data_y_; std::vector external_data_yp_; std::vector interface_partition_externals_; + + size_t bus_port_i_; + size_t bus_port_j_; + IdxT bus_i_; + IdxT bus_j_; }; } // namespace GridKit From be232c71b2242acaf3edaabf964540080dff4109 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Wed, 3 Jun 2026 05:26:09 +0000 Subject: [PATCH 04/34] Updated Hires test problem to implicit form --- .../PowerElectronics/Partition/HiresBus.hpp | 6 +-- .../Partition/HiresComponent1.hpp | 12 ++--- ...iresComponent2.hpp => HiresComponent3.hpp} | 18 +++---- .../PowerElectronics/Partition/Partition.cpp | 48 +++++++++---------- 4 files changed, 42 insertions(+), 42 deletions(-) rename examples/PowerElectronics/Partition/{HiresComponent2.hpp => HiresComponent3.hpp} (81%) diff --git a/examples/PowerElectronics/Partition/HiresBus.hpp b/examples/PowerElectronics/Partition/HiresBus.hpp index a01152ac0..585d25ce0 100644 --- a/examples/PowerElectronics/Partition/HiresBus.hpp +++ b/examples/PowerElectronics/Partition/HiresBus.hpp @@ -5,7 +5,7 @@ namespace GridKit { /*! - * @brief Declaration of a MicrogridLine class. + * @brief Declaration of a Hires Bus Component. * */ template @@ -70,8 +70,8 @@ namespace GridKit int evaluateResidual() { - f_[0] = -y_[0]; - f_[1] = -y_[1]; + f_[0] = yp_[0] + y_[0]; + f_[1] = yp_[1] + y_[1]; return 0; } diff --git a/examples/PowerElectronics/Partition/HiresComponent1.hpp b/examples/PowerElectronics/Partition/HiresComponent1.hpp index 7314264b0..71f4268f5 100644 --- a/examples/PowerElectronics/Partition/HiresComponent1.hpp +++ b/examples/PowerElectronics/Partition/HiresComponent1.hpp @@ -7,7 +7,7 @@ namespace GridKit { /*! - * @brief Declaration of a HiresComponent1 class. + * @brief Declaration of a Hires Component 1 class. * */ template @@ -72,11 +72,11 @@ namespace GridKit int evaluateResidual() { - f_[0] = -1.71 * y_[0] + 0.43 * y_[1] + 8.32 * y_[2] + 0.0007; - f_[1] = 1.71 * y_[0] - 8.75 * y_[1]; - f_[2] = -10.03 * y_[2] + 0.43 * y_[3] + 0.035 * y_[4]; - f_[3] = 8.32 * y_[1] + 1.71 * y_[2] - 0.1 * y_[3]; - f_[4] = -0.7 * y_[4]; + f_[0] = yp_[0] + 1.71 * y_[0] - 0.43 * y_[1] - 8.32 * y_[2] - 0.0007; + f_[1] = yp_[1] - 1.71 * y_[0] + 8.75 * y_[1]; + f_[2] = yp_[2] + 10.03 * y_[2] - 0.43 * y_[3] - 0.035 * y_[4]; + f_[3] = -8.32 * y_[1] - 1.71 * y_[2] + 0.1 * y_[3]; + f_[4] = +0.7 * y_[4]; return 0; } diff --git a/examples/PowerElectronics/Partition/HiresComponent2.hpp b/examples/PowerElectronics/Partition/HiresComponent3.hpp similarity index 81% rename from examples/PowerElectronics/Partition/HiresComponent2.hpp rename to examples/PowerElectronics/Partition/HiresComponent3.hpp index c1787e51a..a396a5e82 100644 --- a/examples/PowerElectronics/Partition/HiresComponent2.hpp +++ b/examples/PowerElectronics/Partition/HiresComponent3.hpp @@ -7,11 +7,11 @@ namespace GridKit { /*! - * @brief Declaration of a HiresComponent1 class. + * @brief Declaration of a Hires Component 3 class. * */ template - class HiresComponent2 : public CircuitComponent + class HiresComponent3 : public CircuitComponent { using RealT = typename CircuitComponent::RealT; using MatrixT = typename CircuitComponent::MatrixT; @@ -38,7 +38,7 @@ namespace GridKit using CircuitComponent::n_intern_; public: - HiresComponent2(IdxT id) + HiresComponent3(IdxT id) { size_ = 5; n_intern_ = 3; @@ -47,7 +47,7 @@ namespace GridKit idc_ = id; } - ~HiresComponent2() + ~HiresComponent3() { } @@ -72,11 +72,11 @@ namespace GridKit int evaluateResidual() { - f_[0] = -280 * y_[0] * y_[2] + 0.69 * y_[3] + 1.71 * y_[4] - 0.43 * y_[0] + 0.69 * y_[1]; - f_[1] = 280 * y_[0] * y_[2] - 1.81 * y_[1]; - f_[2] = -280 * y_[0] * y_[2] + 1.81 * y_[1]; - f_[3] = -0.02 * y_[3]; - f_[4] = -0.045 * y_[4] + 0.43 * y_[0] + 0.43 * y_[1]; + f_[0] = yp_[0] + 280 * y_[0] * y_[2] - 0.69 * y_[3] - 1.71 * y_[4] + 0.43 * y_[0] - 0.69 * y_[1]; + f_[1] = yp_[1] - 280 * y_[0] * y_[2] + 1.81 * y_[1]; + f_[2] = yp_[2] + 280 * y_[0] * y_[2] - 1.81 * y_[1]; + f_[3] = 0.02 * y_[3]; + f_[4] = 0.045 * y_[4] - 0.43 * y_[0] - 0.43 * y_[1]; return 0; } diff --git a/examples/PowerElectronics/Partition/Partition.cpp b/examples/PowerElectronics/Partition/Partition.cpp index 67afcd264..b02285fbd 100644 --- a/examples/PowerElectronics/Partition/Partition.cpp +++ b/examples/PowerElectronics/Partition/Partition.cpp @@ -11,9 +11,9 @@ #include "HiresBus.hpp" #include "HiresComponent1.hpp" -#include "HiresComponent2.hpp" +#include "HiresComponent3.hpp" -std::vector hires(std::vector y); +std::vector hires(const std::vector& y, const std::vector& yp); int main(int /* argc */, char const** /* argv */) { @@ -28,7 +28,7 @@ int main(int /* argc */, char const** /* argv */) GridKit::HiresComponent1* comp1 = new GridKit::HiresComponent1(1); GridKit::HiresBus* bus1 = new GridKit::HiresBus(2); - GridKit::HiresComponent2* comp2 = new GridKit::HiresComponent2(3); + GridKit::HiresComponent3* comp3 = new GridKit::HiresComponent3(3); comp1->setExternalConnectionNodes(0, 0); comp1->setExternalConnectionNodes(1, 1); @@ -39,18 +39,15 @@ int main(int /* argc */, char const** /* argv */) bus1->setExternalConnectionNodes(0, 3); bus1->setExternalConnectionNodes(1, 4); - comp2->setExternalConnectionNodes(0, 5); - comp2->setExternalConnectionNodes(1, 6); - comp2->setExternalConnectionNodes(2, 7); - comp2->setExternalConnectionNodes(3, 3); - comp2->setExternalConnectionNodes(4, 4); + comp3->setExternalConnectionNodes(0, 5); + comp3->setExternalConnectionNodes(1, 6); + comp3->setExternalConnectionNodes(2, 7); + comp3->setExternalConnectionNodes(3, 3); + comp3->setExternalConnectionNodes(4, 4); - GridKit::HiresComponent2 comp2copy(*comp2); - GridKit::BusPartitionInterface* busInterface = new GridKit::BusPartitionInterface(comp2copy, 10); - GridKit::ComponentPartitionInterface* compInterface = new GridKit::ComponentPartitionInterface(comp2, 3, 4, 9); - - busInterface->setExternalConnectionNodes(0, 3); - busInterface->setExternalConnectionNodes(1, 4); + GridKit::HiresComponent3 comp2copy(*comp3); + GridKit::BusPartitionInterface* busInterface = new GridKit::BusPartitionInterface(comp2copy, 3, 4, 4); + GridKit::ComponentPartitionInterface* compInterface = new GridKit::ComponentPartitionInterface(comp3, 3, 4, 5); partition1->addComponent(comp1); partition1->addComponent(bus1); @@ -64,7 +61,10 @@ int main(int /* argc */, char const** /* argv */) partition2->allocate(sys_size); busInterface->setExternalDataY({6, 7, 8}); + busInterface->setExternalDataYP({6, 7, 8}); + compInterface->setExternalDataY({4, 5}); + compInterface->setExternalDataYP({4, 5}); for (size_t i = 0; i < sys_size; i++) { @@ -79,7 +79,7 @@ int main(int /* argc */, char const** /* argv */) partition1->evaluateResidual(); partition2->evaluateResidual(); - auto ref = hires({1, 2, 3, 4, 5, 6, 7, 8}); + auto ref = hires({1, 2, 3, 4, 5, 6, 7, 8}, {1, 2, 3, 4, 5, 6, 7, 8}); std::cout << "------------- Partition 1 -----------" << std::endl; for (size_t i = 0; i < sys_size; i++) @@ -97,18 +97,18 @@ int main(int /* argc */, char const** /* argv */) delete partition2; } -std::vector hires(std::vector y) +std::vector hires(const std::vector& y, const std::vector& yp) { std::vector f(8); - f[0] = -1.71 * y[0] + 0.43 * y[1] + 8.32 * y[2] + 0.0007; - f[1] = 1.71 * y[0] - 8.75 * y[1]; - f[2] = -10.03 * y[2] + 0.43 * y[3] + 0.035 * y[4]; - f[3] = 8.32 * y[1] + 1.71 * y[2] - 1.12 * y[3]; - f[4] = -1.745 * y[4] + 0.43 * y[5] + 0.43 * y[6]; - f[5] = -280 * y[5] * y[7] + 0.69 * y[3] + 1.71 * y[4] - 0.43 * y[5] + 0.69 * y[6]; - f[6] = 280 * y[5] * y[7] - 1.81 * y[6]; - f[7] = -280 * y[5] * y[7] + 1.81 * y[6]; + f[0] = yp[0] + 1.71 * y[0] - 0.43 * y[1] - 8.32 * y[2] - 0.0007; + f[1] = yp[1] - 1.71 * y[0] + 8.75 * y[1]; + f[2] = yp[2] + 10.03 * y[2] - 0.43 * y[3] - 0.035 * y[4]; + f[3] = yp[3] - 8.32 * y[1] - 1.71 * y[2] + 1.12 * y[3]; + f[4] = yp[4] + 1.745 * y[4] - 0.43 * y[5] - 0.43 * y[6]; + f[5] = yp[5] + 280 * y[5] * y[7] - 0.69 * y[3] - 1.71 * y[4] + 0.43 * y[5] - 0.69 * y[6]; + f[6] = yp[6] - 280 * y[5] * y[7] + 1.81 * y[6]; + f[7] = yp[7] + 280 * y[5] * y[7] - 1.81 * y[6]; return f; } From 6d79ba421670c46c025384cde381aae3fa9b35d7 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Wed, 3 Jun 2026 19:53:32 +0000 Subject: [PATCH 05/34] Change comments in partition interfaces --- .../PartitionInterface/BusPartitionInterface.cpp | 2 +- .../PartitionInterface/BusPartitionInterface.hpp | 1 - .../ComponentPartitionInterface.cpp | 13 +++++-------- examples/PowerElectronics/Partition/Partition.cpp | 4 ++-- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp index b2c806b26..e275c6b39 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp @@ -44,7 +44,7 @@ namespace GridKit } /*! - * @brief allocate method computes sparsity pattern of the Jacobian. + * @brief allocate method */ template int BusPartitionInterface::allocate() diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp index 1b1d9e4bd..0c8b2e902 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp @@ -5,7 +5,6 @@ #include #include - #include "GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp" namespace GridKit diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.cpp b/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.cpp index 3c88c4dee..c5a06ae66 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.cpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.cpp @@ -11,9 +11,8 @@ namespace GridKit { /*! - * @brief Constructor for a constant MicrogridLoad model + * @brief Constructor for the ComponentPartitionInterface * - * Calls default ModelEvaluatorImpl constructor. * * * @@ -23,8 +22,6 @@ namespace GridKit ComponentPartitionInterface::ComponentPartitionInterface(CircuitComponent* component, IdxT bus_i, IdxT bus_j, IdxT id) : component_(component) { - // internals [id, iq] - // externals [\omegaref, vbd_out, vbq_out] size_ = component_->size(); n_intern_ = component_->getInternalSize(); n_extern_ = component_->getExternSize(); @@ -41,7 +38,7 @@ namespace GridKit } /*! - * @brief allocate method computes sparsity pattern of the Jacobian. + * @brief allocate method. */ template int ComponentPartitionInterface::allocate() @@ -85,7 +82,7 @@ namespace GridKit } /** - * Initialization of the grid model + * Initialization */ template int ComponentPartitionInterface::initialize() @@ -94,7 +91,7 @@ namespace GridKit } /* - * \brief Identify differential variables + * */ template int ComponentPartitionInterface::tagDifferentiable() @@ -103,7 +100,7 @@ namespace GridKit } /** - * @brief Eval Micro Load + * @brief */ template int ComponentPartitionInterface::evaluateResidual() diff --git a/examples/PowerElectronics/Partition/Partition.cpp b/examples/PowerElectronics/Partition/Partition.cpp index b02285fbd..92f2d60ff 100644 --- a/examples/PowerElectronics/Partition/Partition.cpp +++ b/examples/PowerElectronics/Partition/Partition.cpp @@ -45,8 +45,8 @@ int main(int /* argc */, char const** /* argv */) comp3->setExternalConnectionNodes(3, 3); comp3->setExternalConnectionNodes(4, 4); - GridKit::HiresComponent3 comp2copy(*comp3); - GridKit::BusPartitionInterface* busInterface = new GridKit::BusPartitionInterface(comp2copy, 3, 4, 4); + GridKit::HiresComponent3 comp3copy(*comp3); + GridKit::BusPartitionInterface* busInterface = new GridKit::BusPartitionInterface(comp3copy, 3, 4, 4); GridKit::ComponentPartitionInterface* compInterface = new GridKit::ComponentPartitionInterface(comp3, 3, 4, 5); partition1->addComponent(comp1); From a4ec893fc40ca4db82a6bf1cef2ceade231f1dc1 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Mon, 15 Jun 2026 01:36:06 +0000 Subject: [PATCH 06/34] Added a subsystem model for evaluating partitions --- GridKit/Model/PowerElectronics/CMakeLists.txt | 2 + .../Model/PowerElectronics/SubsystemModel.hpp | 452 ++++++++++++++++++ .../PowerElectronics/Partition/CMakeLists.txt | 8 + .../Partition/HiresComponent1.hpp | 16 +- .../Partition/HiresComponent3.hpp | 15 +- .../PowerElectronics/Partition/Partition.cpp | 110 +++-- 6 files changed, 548 insertions(+), 55 deletions(-) create mode 100644 GridKit/Model/PowerElectronics/SubsystemModel.hpp diff --git a/GridKit/Model/PowerElectronics/CMakeLists.txt b/GridKit/Model/PowerElectronics/CMakeLists.txt index bdedb72e3..199df1684 100644 --- a/GridKit/Model/PowerElectronics/CMakeLists.txt +++ b/GridKit/Model/PowerElectronics/CMakeLists.txt @@ -29,4 +29,6 @@ install( CircuitGraph.hpp SystemModelPowerElectronics.hpp NodeBase.hpp + SubsystemModel.hpp DESTINATION include/GridKit/Model/PowerElectronics) + diff --git a/GridKit/Model/PowerElectronics/SubsystemModel.hpp b/GridKit/Model/PowerElectronics/SubsystemModel.hpp new file mode 100644 index 000000000..af3d9dc9f --- /dev/null +++ b/GridKit/Model/PowerElectronics/SubsystemModel.hpp @@ -0,0 +1,452 @@ + + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.hpp" + +namespace GridKit +{ + template + class SubsystemModel : public CircuitComponent + { + using RealT = typename CircuitComponent::RealT; + using MatrixT = typename CircuitComponent::MatrixT; + using CsrMatrixT = typename CircuitComponent::CsrMatrixT; + using component_type = CircuitComponent; + using node_type = CircuitNode; + + using CircuitComponent::size_; + using CircuitComponent::n_extern_; + using CircuitComponent::n_intern_; + using CircuitComponent::nnz_; + using CircuitComponent::time_; + using CircuitComponent::alpha_; + using CircuitComponent::y_; + using CircuitComponent::yp_; + using CircuitComponent::f_; + using CircuitComponent::jac_; + using CircuitComponent::rel_tol_; + using CircuitComponent::abs_tol_; + + public: + /** + * @brief Default constructor for the system model + * + * @post System model parameters set as default + */ + SubsystemModel(IdxT refframe_index = neg1_) + { + // Set system model parameters as default + rel_tol_ = 1e-4; + abs_tol_ = 1e-4; + this->max_steps_ = 2000; + // By default don't use the jacobian + use_jac_ = false; + refframe_index_ = refframe_index; + } + + virtual ~SubsystemModel() + { + for (auto comp : this->components_) + { + delete comp; + } + delete csr_jac_; + delete[] map_to_csr_; + } + + bool hasJacobian() final + { + if (!this->use_jac_) + return false; + + for (const auto& component : components_) + { + if (!component->hasJacobian()) + { + return false; + } + } + return true; + } + + int allocate() override + { + // Allocate all components + size_ = 0; + n_extern_ = 0; + n_intern_ = 0; + + size_t counter = 0; + + // First pass: Map global component indices to local subsystem indices. + for (const auto& component : components_) + { + component->allocate(); + + for (IdxT i = component->getExternSize(); i < component->size(); i++) + { + + IdxT index = component->getNodeConnection(i); + + if (index != neg1_) + { + internal_map_[index] = counter; + n_intern_++; + counter++; + } + } + + // TODO : To be removed once MicrogridBusDQ owns its internals + auto* comp = dynamic_cast*>(component); + + if (comp != nullptr) + { + IdxT index1 = component->getNodeConnection(0); + IdxT index2 = component->getNodeConnection(1); + + internal_map_[index1] = counter; + counter++; + internal_map_[index2] = counter; + counter++; + n_intern_ += 2; + } + } + + if (refframe_index_ != neg1_) + { + internal_map_[refframe_index_] = counter; + n_intern_++; + counter++; + } + + // Second pass: Identify variables required by this partition but owned by + // another partition. + for (const auto& component : components_) + { + for (IdxT i = 0; i < component->getExternSize(); i++) + { + IdxT index = component->getNodeConnection(i); + + if (internal_map_.count(index) < 1 && external_map_.count(index) < 1 && index != neg1_) + { + external_map_[index] = counter; + + counter++; + n_extern_++; + } + } + } + + size_ = n_intern_ + n_extern_; + + this->mapGlobalToLocal(); + + // Allocate subsystem vectors. + y_.resize(n_intern_); + yp_.resize(n_intern_); + f_.resize(n_intern_); + + // Allocate vectors associated with external coupling variables. + y_ext_.resize(n_extern_); + yp_ext_.resize(n_extern_); + f_ext_.resize(n_extern_); + external_indices_.resize(n_extern_); + + // Store the mapping from local subsystem indices back to their global system indices + for (const auto& [global_idx, local_idx] : internal_map_) + { + this->setExternalConnectionNodes(local_idx, global_idx); + } + + // Store the global indices of all external coupling variables. + for (const auto& [global_idx, local_idx] : external_map_) + { + external_indices_[local_idx - n_intern_] = global_idx; + } + + return 0; + } + + /** + * @brief Set intial y and y' of each component + * + * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable + */ + int initialize() final + { + // Initialize components + for (const auto& component : components_) + { + component->initialize(); + } + 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() + { + for (const auto& component : components_) + { + 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_) + { + y[j] = 0.0; + yp[j] = 0.0; + } + else if (component->getNodeConnection(j) < this->getInternalSize()) + { + y[j] = y_[component->getNodeConnection(j)]; + yp[j] = yp_[component->getNodeConnection(j)]; + } + else + { + y[j] = y_ext_[component->getNodeConnection(j) - this->getInternalSize()]; + yp[j] = yp_ext_[component->getNodeConnection(j) - this->getInternalSize()]; + } + } + } + return 0; + } + + int tagDifferentiable() final + { + return 0; + } + + /** + * @brief Evaluate Residuals at each component then collect them + * + * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable + */ + int evaluateResidual() final + { + for (IdxT i = 0; i < this->f_.size(); i++) + { + f_[i] = 0.0; + } + + this->distributeVectors(); + + // Update system residual vector + for (const auto& component : components_) + { + // TODO:check return type + component->evaluateResidual(); + + 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_ && component->getNodeConnection(j) < this->getInternalSize()) + { + f_[component->getNodeConnection(j)] += residual[j]; + } + } + } + + return 0; + } + + /** + * @brief Creates the system Jacobian representing \alpha dF/dy' + dF/dy + * + * Updates the CSR Jacobian values using the per-component mappings + * computed during allocate(). + * + * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable + */ + int evaluateJacobian() final + { + return 0; + } + + /** + * @brief Evaluate integrands for the system quadratures. + */ + int evaluateIntegrand() final + { + return 0; + } + + /** + * @brief Initialize system adjoint. + * + * Updates variables and optimization parameters, then initializes + * adjoints locally and copies them to the system adjoint vector. + */ + int initializeAdjoint() final + { + return 0; + } + + /** + * @brief Compute adjoint residual for the system model. + * + * + */ + int evaluateAdjointResidual() final + { + return 0; + } + + /** + * @brief Evaluate adjoint integrand for the system model. + * + * + */ + int evaluateAdjointIntegrand() final + { + return 0; + } + + /** + * @brief Distribute time and time scaling for each component + * + * @param t + * @param a + */ + void updateTime(RealT t, RealT a) final + { + for (const auto& component : components_) + { + component->updateTime(t, a); + } + time_ = t; + alpha_ = a; + } + + /** + * @brief print the system residual in COO format + * + * @param[in] filename + * @param[in] title + */ + void printResidualMatrixMarket(std::string filename, std::string title) + { + writeVectorToMatrixMarket(f_, filename, title); + } + + /** + * @brief print the system Jacobian in COO format + * + * @param[in] filename + * @param[in] title + */ + void printJacobianMatrixMarket(std::string filename, std::string title) + { + jac_.printMatrixMarket(filename, title); + } + + CsrMatrixT* getCsrJacobian() const override + { + return csr_jac_; + } + + void addComponent(component_type* component) + { + components_.push_back(component); + } + + std::unordered_map& getInternalMap() + { + return internal_map_; + } + + std::unordered_map& getExternalMap() + { + return external_map_; + } + + int mapGlobalToLocal() + { + for (const auto& component : components_) + { + + for (IdxT i = 0; i < component->size(); i++) + { + IdxT index = component->getNodeConnection(i); + + if (index == neg1_) + { + continue; + } + else if (internal_map_.count(index) > 0) + { + component->setExternalConnectionNodes(i, internal_map_.at(index)); + } + else + { + component->setExternalConnectionNodes(i, external_map_.at(index)); + } + } + } + + return 0; + } + + int mapLocalToGlobal() + { + return 0; + } + + std::vector& getExternalDataY() + { + return y_ext_; + } + + std::vector& getExternalDataYP() + { + return yp_ext_; + } + + std::vector& getExternalIndices() + { + return external_indices_; + } + + private: + static constexpr IdxT neg1_ = INVALID_INDEX; + + std::vector components_; + std::unordered_map internal_map_; + std::unordered_map external_map_; + std::vector external_indices_; + std::vector y_ext_; + std::vector yp_ext_; + std::vector f_ext_; + IdxT refframe_index_{neg1_}; + + IdxT* map_to_csr_{nullptr}; + CsrMatrixT* csr_jac_{nullptr}; + + int jac_call_count_{0}; + bool use_jac_; + + }; // class SubsystemModel + +} // namespace GridKit diff --git a/examples/PowerElectronics/Partition/CMakeLists.txt b/examples/PowerElectronics/Partition/CMakeLists.txt index a5d192a9d..2bc268e4f 100644 --- a/examples/PowerElectronics/Partition/CMakeLists.txt +++ b/examples/PowerElectronics/Partition/CMakeLists.txt @@ -2,3 +2,11 @@ add_executable(partition Partition.cpp) target_link_libraries(partition GridKit::solvers_dyn GridKit::power_elec_partition_interfaces) + +add_executable(partitionMicrogrid PartitionMicrogrid.cpp) +target_link_libraries(partitionMicrogrid GridKit::power_elec_disgen + GridKit::power_elec_microline + GridKit::power_elec_microload + GridKit::solvers_dyn + GridKit::power_elec_microbusdq + GridKit::power_elec_partition_interfaces) \ No newline at end of file diff --git a/examples/PowerElectronics/Partition/HiresComponent1.hpp b/examples/PowerElectronics/Partition/HiresComponent1.hpp index 71f4268f5..1d6c51fc8 100644 --- a/examples/PowerElectronics/Partition/HiresComponent1.hpp +++ b/examples/PowerElectronics/Partition/HiresComponent1.hpp @@ -43,7 +43,7 @@ namespace GridKit size_ = 5; n_intern_ = 3; n_extern_ = 2; - extern_indices_ = {3, 4}; + extern_indices_ = {0, 1}; idc_ = id; } @@ -72,11 +72,15 @@ namespace GridKit int evaluateResidual() { - f_[0] = yp_[0] + 1.71 * y_[0] - 0.43 * y_[1] - 8.32 * y_[2] - 0.0007; - f_[1] = yp_[1] - 1.71 * y_[0] + 8.75 * y_[1]; - f_[2] = yp_[2] + 10.03 * y_[2] - 0.43 * y_[3] - 0.035 * y_[4]; - f_[3] = -8.32 * y_[1] - 1.71 * y_[2] + 0.1 * y_[3]; - f_[4] = +0.7 * y_[4]; + + // outputs + f_[0] = -8.32 * y_[3] - 1.71 * y_[4] + 0.1 * y_[0]; + f_[1] = +0.7 * y_[1]; + + // Internals + f_[2] = yp_[2] + 1.71 * y_[2] - 0.43 * y_[3] - 8.32 * y_[4] - 0.0007; + f_[3] = yp_[3] - 1.71 * y_[2] + 8.75 * y_[3]; + f_[4] = yp_[4] + 10.03 * y_[4] - 0.43 * y_[0] - 0.035 * y_[1]; return 0; } diff --git a/examples/PowerElectronics/Partition/HiresComponent3.hpp b/examples/PowerElectronics/Partition/HiresComponent3.hpp index a396a5e82..d0b71f5c1 100644 --- a/examples/PowerElectronics/Partition/HiresComponent3.hpp +++ b/examples/PowerElectronics/Partition/HiresComponent3.hpp @@ -43,7 +43,7 @@ namespace GridKit size_ = 5; n_intern_ = 3; n_extern_ = 2; - extern_indices_ = {3, 4}; + extern_indices_ = {0, 1}; idc_ = id; } @@ -72,11 +72,14 @@ namespace GridKit int evaluateResidual() { - f_[0] = yp_[0] + 280 * y_[0] * y_[2] - 0.69 * y_[3] - 1.71 * y_[4] + 0.43 * y_[0] - 0.69 * y_[1]; - f_[1] = yp_[1] - 280 * y_[0] * y_[2] + 1.81 * y_[1]; - f_[2] = yp_[2] + 280 * y_[0] * y_[2] - 1.81 * y_[1]; - f_[3] = 0.02 * y_[3]; - f_[4] = 0.045 * y_[4] - 0.43 * y_[0] - 0.43 * y_[1]; + // Outputs + f_[0] = 0.02 * y_[0]; + f_[1] = 0.045 * y_[1] - 0.43 * y_[2] - 0.43 * y_[3]; + + // Internals + f_[2] = yp_[2] + 280 * y_[2] * y_[4] - 0.69 * y_[0] - 1.71 * y_[1] + 0.43 * y_[2] - 0.69 * y_[3]; + f_[3] = yp_[3] - 280 * y_[2] * y_[4] + 1.81 * y_[3]; + f_[4] = yp_[4] + 280 * y_[2] * y_[4] - 1.81 * y_[3]; return 0; } diff --git a/examples/PowerElectronics/Partition/Partition.cpp b/examples/PowerElectronics/Partition/Partition.cpp index 92f2d60ff..319e4dc00 100644 --- a/examples/PowerElectronics/Partition/Partition.cpp +++ b/examples/PowerElectronics/Partition/Partition.cpp @@ -4,10 +4,10 @@ #include #include #include +#include #include -#include -#include +#include #include "HiresBus.hpp" #include "HiresComponent1.hpp" @@ -18,79 +18,103 @@ std::vector hires(const std::vector& y, const std::vector(rel_tol, abs_tol, use_jac, max_step_number); - auto* partition2 = new GridKit::PowerElectronicsModel(rel_tol, abs_tol, use_jac, max_step_number); + GridKit::SubsystemModel* partition1 = new GridKit::SubsystemModel(); + GridKit::SubsystemModel* partition2 = new GridKit::SubsystemModel(); GridKit::HiresComponent1* comp1 = new GridKit::HiresComponent1(1); GridKit::HiresBus* bus1 = new GridKit::HiresBus(2); GridKit::HiresComponent3* comp3 = new GridKit::HiresComponent3(3); - comp1->setExternalConnectionNodes(0, 0); - comp1->setExternalConnectionNodes(1, 1); - comp1->setExternalConnectionNodes(2, 2); - comp1->setExternalConnectionNodes(3, 3); - comp1->setExternalConnectionNodes(4, 4); + comp1->setExternalConnectionNodes(0, 3); + comp1->setExternalConnectionNodes(1, 4); + comp1->setExternalConnectionNodes(2, 0); + comp1->setExternalConnectionNodes(3, 1); + comp1->setExternalConnectionNodes(4, 2); bus1->setExternalConnectionNodes(0, 3); bus1->setExternalConnectionNodes(1, 4); - comp3->setExternalConnectionNodes(0, 5); - comp3->setExternalConnectionNodes(1, 6); - comp3->setExternalConnectionNodes(2, 7); - comp3->setExternalConnectionNodes(3, 3); - comp3->setExternalConnectionNodes(4, 4); + comp3->setExternalConnectionNodes(0, 3); + comp3->setExternalConnectionNodes(1, 4); + comp3->setExternalConnectionNodes(2, 5); + comp3->setExternalConnectionNodes(3, 6); + comp3->setExternalConnectionNodes(4, 7); - GridKit::HiresComponent3 comp3copy(*comp3); - GridKit::BusPartitionInterface* busInterface = new GridKit::BusPartitionInterface(comp3copy, 3, 4, 4); - GridKit::ComponentPartitionInterface* compInterface = new GridKit::ComponentPartitionInterface(comp3, 3, 4, 5); + GridKit::HiresComponent3 comp3copy(*comp3); + GridKit::BusPartitionInterface* busInterface = new GridKit::BusPartitionInterface(comp3copy, 3, 4, 4); partition1->addComponent(comp1); partition1->addComponent(bus1); partition1->addComponent(busInterface); - partition2->addComponent(compInterface); - - size_t sys_size = 8; + partition2->addComponent(comp3); - partition1->allocate(sys_size); - partition2->allocate(sys_size); + partition1->allocate(); + partition2->allocate(); - busInterface->setExternalDataY({6, 7, 8}); - busInterface->setExternalDataYP({6, 7, 8}); + std::vector y = {1, 2, 3, 4, 5, 6, 7, 8}; + std::vector yp = {1, 2, 3, 4, 5, 6, 7, 8}; - compInterface->setExternalDataY({4, 5}); - compInterface->setExternalDataYP({4, 5}); + // Distribute externals to partition 1 + for (size_t i = 0; i < partition1->getExternSize(); i++) + { + partition1->getExternalDataY()[i] = y[partition1->getExternalIndices()[i]]; + partition1->getExternalDataYP()[i] = yp[partition1->getExternalIndices()[i]]; + } - for (size_t i = 0; i < sys_size; i++) + // Distribute externals to partition 2 + for (size_t i = 0; i < partition2->getExternSize(); i++) { + partition2->getExternalDataY()[i] = y[partition2->getExternalIndices()[i]]; + partition2->getExternalDataYP()[i] = yp[partition2->getExternalIndices()[i]]; + } - partition1->y()[i] = static_cast(i) + 1; - partition1->yp()[i] = static_cast(i) + 1; + // Distribute internals to partition 1 + for (size_t i = 0; i < partition1->getInternalSize(); i++) + { + partition1->y()[i] = static_cast(1 + i); + partition1->yp()[i] = static_cast(1 + i); + } - partition2->y()[i] = static_cast(i) + 1; - partition2->yp()[i] = static_cast(i) + 1; + // Distribute internals to partition 2 + for (size_t i = 0; i < partition2->getInternalSize(); i++) + { + partition2->y()[i] = static_cast(6 + i); + partition2->yp()[i] = static_cast(6 + i); } + // Evaluate Residuals for each partition partition1->evaluateResidual(); partition2->evaluateResidual(); - auto ref = hires({1, 2, 3, 4, 5, 6, 7, 8}, {1, 2, 3, 4, 5, 6, 7, 8}); + auto printTitle = [](std::string msg) -> void + { + std::cout << "\n------------- " << msg << " -----------" << std::endl; + printf("%-10s ---------- %10s\n", "Res Values", "Comp. Index"); + }; + + // Print Residuals from partition 1 + printTitle("Partition 1"); + for (size_t i = 0; i < partition1->getInternalSize(); i++) + { + auto com_index = partition1->getNodeConnection(static_cast(i)); + printf("%-10.5g ---------- %10zu\n", partition1->getResidual()[i], com_index); + } - std::cout << "------------- Partition 1 -----------" << std::endl; - for (size_t i = 0; i < sys_size; i++) + // Print Residuals from partition 2 + printTitle("Partition 2"); + for (size_t i = 0; i < partition2->getInternalSize(); i++) { - printf("%-10.5g ---------- %10.5g\n", partition1->getResidual()[i], ref[i]); + auto com_index = partition2->getNodeConnection(static_cast(i)); + printf("%-10.5g ---------- %10zu\n", partition2->getResidual()[i], com_index); } - std::cout << "\n------------- Partition 2 -----------" << std::endl; - for (size_t i = 0; i < sys_size; i++) + auto ref = hires(y, yp); + + printTitle("Reference Solution"); + for (size_t i = 0; i < 8; i++) { - printf("%-10.5g ---------- %10.5g\n", partition2->getResidual()[i], ref[i]); + printf("%-10.5g ---------- %10zu\n", ref[i], i); } delete partition1; From 5f99b22671d3cd6ae1a3a03d26ce00eda135ef04 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Mon, 15 Jun 2026 01:43:51 +0000 Subject: [PATCH 07/34] Added a partitioned microgrid test problem --- .../Partition/PartitionMicrogrid.cpp | 392 ++++++++++++++++++ 1 file changed, 392 insertions(+) create mode 100644 examples/PowerElectronics/Partition/PartitionMicrogrid.cpp diff --git a/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp b/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp new file mode 100644 index 000000000..4a961caa8 --- /dev/null +++ b/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp @@ -0,0 +1,392 @@ +#include + +#define _USE_MATH_DEFINES +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +int main() +{ + /// @todo Needs to be modified. Some components are small relative to others thus + /// there error is high (or could be matlab vector issue) + double abs_tol = 1.0e-8; + double rel_tol = 1.0e-8; + size_t max_step_number = 3000; + bool use_jac = true; + + auto* sysmodel = new GridKit::PowerElectronicsModel(rel_tol, abs_tol, use_jac, max_step_number); + + // Modeled after the problem in the paper + double RN = 1.0e4; + + // DG Params + GridKit::DistributedGeneratorParameters parms1; + parms1.wb_ = 2.0 * M_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 * M_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 * M_PI * 50.0); + + double rline2 = 0.35; + double Lline2 = 0.58 / (2.0 * M_PI * 50.0); + + double rline3 = 0.23; + double Lline3 = 0.1 / (2.0 * M_PI * 50.0); + + // load parms + double rload1 = 3.0; + double Lload1 = 2.0 / (2.0 * M_PI * 50.0); + + double rload2 = 2.0; + double Lload2 = 1.0 / (2.0 * M_PI * 50.0); + + // indexing sets + size_t Nsize = 2; + // DGs + - refframe Lines + Loads + size_t vec_size_internals = 13 * (2 * Nsize) - 1 + (2 + 4 * (Nsize - 1)) + 2 * Nsize; + // \omegaref + BusDQ + size_t vec_size_externals = 1 + 2 * (2 * Nsize); + size_t dqbus1 = vec_size_internals + 1; + size_t dqbus2 = vec_size_internals + 3; + size_t dqbus3 = vec_size_internals + 5; + size_t dqbus4 = vec_size_internals + 7; + + size_t vec_size_total = vec_size_internals + vec_size_externals; + + size_t indexv = 0; + + // dg 1 + GridKit::DistributedGenerator* dg1 = new GridKit::DistributedGenerator(0, parms1, true); + // ref motor + dg1->setExternalConnectionNodes(0, vec_size_internals); + // outputs + dg1->setExternalConnectionNodes(1, dqbus1); + dg1->setExternalConnectionNodes(2, dqbus1 + 1); + //"grounding" of the difference + dg1->setExternalConnectionNodes(3, static_cast(-1)); + // internal connections + for (size_t i = 0; i < 12; i++) + { + + dg1->setExternalConnectionNodes(4 + i, indexv + i); + } + indexv += 12; + + // dg 2 + GridKit::DistributedGenerator* dg2 = new GridKit::DistributedGenerator(1, parms1, false); + // ref motor + dg2->setExternalConnectionNodes(0, vec_size_internals); + // outputs + dg2->setExternalConnectionNodes(1, dqbus2); + dg2->setExternalConnectionNodes(2, dqbus2 + 1); + // internal connections + for (size_t i = 0; i < 13; i++) + { + + dg2->setExternalConnectionNodes(3 + i, indexv + i); + } + indexv += 13; + + // dg 3 + GridKit::DistributedGenerator* dg3 = new GridKit::DistributedGenerator(2, parms2, false); + // ref motor + dg3->setExternalConnectionNodes(0, vec_size_internals); + // outputs + dg3->setExternalConnectionNodes(1, dqbus3); + dg3->setExternalConnectionNodes(2, dqbus3 + 1); + // internal connections + for (size_t i = 0; i < 13; i++) + { + + dg3->setExternalConnectionNodes(3 + i, indexv + i); + } + indexv += 13; + + // dg 4 + GridKit::DistributedGenerator* dg4 = new GridKit::DistributedGenerator(3, parms2, false); + // ref motor + dg4->setExternalConnectionNodes(0, vec_size_internals); + // outputs + dg4->setExternalConnectionNodes(1, dqbus4); + dg4->setExternalConnectionNodes(2, dqbus4 + 1); + + // internal connections + for (size_t i = 0; i < 13; i++) + { + + dg4->setExternalConnectionNodes(3 + i, indexv + i); + } + indexv += 13; + + // Lines + + // line 1 + GridKit::MicrogridLine* l1 = new GridKit::MicrogridLine(4, rline1, Lline1); + // ref motor + l1->setExternalConnectionNodes(0, vec_size_internals); + // input connections + l1->setExternalConnectionNodes(1, dqbus1); + l1->setExternalConnectionNodes(2, dqbus1 + 1); + // output connections + l1->setExternalConnectionNodes(3, dqbus2); + l1->setExternalConnectionNodes(4, dqbus2 + 1); + // internal connections + for (size_t i = 0; i < 2; i++) + { + + l1->setExternalConnectionNodes(5 + i, indexv + i); + } + indexv += 2; + + // line 2 + GridKit::MicrogridLine* l2 = new GridKit::MicrogridLine(5, rline2, Lline2); + // ref motor + l2->setExternalConnectionNodes(0, vec_size_internals); + // input connections + l2->setExternalConnectionNodes(1, dqbus2); + l2->setExternalConnectionNodes(2, dqbus2 + 1); + // output connections + l2->setExternalConnectionNodes(3, dqbus3); + l2->setExternalConnectionNodes(4, dqbus3 + 1); + // internal connections + for (size_t i = 0; i < 2; i++) + { + + l2->setExternalConnectionNodes(5 + i, indexv + i); + } + indexv += 2; + + // line 3 + GridKit::MicrogridLine* l3 = new GridKit::MicrogridLine(6, rline3, Lline3); + // ref motor + l3->setExternalConnectionNodes(0, vec_size_internals); + // input connections + l3->setExternalConnectionNodes(1, dqbus3); + l3->setExternalConnectionNodes(2, dqbus3 + 1); + // output connections + l3->setExternalConnectionNodes(3, dqbus4); + l3->setExternalConnectionNodes(4, dqbus4 + 1); + // internal connections + for (size_t i = 0; i < 2; i++) + { + + l3->setExternalConnectionNodes(5 + i, indexv + i); + } + indexv += 2; + + // loads + + // load 1 + GridKit::MicrogridLoad* load1 = new GridKit::MicrogridLoad(7, rload1, Lload1); + // ref motor + load1->setExternalConnectionNodes(0, vec_size_internals); + // input connections + load1->setExternalConnectionNodes(1, dqbus1); + load1->setExternalConnectionNodes(2, dqbus1 + 1); + // internal connections + for (size_t i = 0; i < 2; i++) + { + + load1->setExternalConnectionNodes(3 + i, indexv + i); + } + indexv += 2; + + // load 2 + GridKit::MicrogridLoad* load2 = new GridKit::MicrogridLoad(8, rload2, Lload2); + // ref motor + load2->setExternalConnectionNodes(0, vec_size_internals); + // input connections + load2->setExternalConnectionNodes(1, dqbus3); + load2->setExternalConnectionNodes(2, dqbus3 + 1); + // internal connections + for (size_t i = 0; i < 2; i++) + { + + load2->setExternalConnectionNodes(3 + i, indexv + i); + } + indexv += 2; + + // Virtual PQ Buses + GridKit::MicrogridBusDQ* bus1 = new GridKit::MicrogridBusDQ(9, RN); + + bus1->setExternalConnectionNodes(0, dqbus1); + bus1->setExternalConnectionNodes(1, dqbus1 + 1); + + GridKit::MicrogridBusDQ* bus2 = new GridKit::MicrogridBusDQ(10, RN); + + bus2->setExternalConnectionNodes(0, dqbus2); + bus2->setExternalConnectionNodes(1, dqbus2 + 1); + + GridKit::MicrogridBusDQ* bus3 = new GridKit::MicrogridBusDQ(11, RN); + + bus3->setExternalConnectionNodes(0, dqbus3); + bus3->setExternalConnectionNodes(1, dqbus3 + 1); + + GridKit::MicrogridBusDQ* bus4 = new GridKit::MicrogridBusDQ(12, RN); + + bus4->setExternalConnectionNodes(0, dqbus4); + bus4->setExternalConnectionNodes(1, dqbus4 + 1); + + GridKit::SubsystemModel* partition1 = new GridKit::SubsystemModel(vec_size_internals); + GridKit::SubsystemModel* partition2 = new GridKit::SubsystemModel(); + + GridKit::MicrogridLine comp3copy(*l2); + GridKit::BusPartitionInterface* busInterface = new GridKit::BusPartitionInterface(comp3copy, dqbus2, dqbus2 + 1, 14); + + partition1->addComponent(dg1); + partition1->addComponent(dg2); + partition1->addComponent(l1); + partition1->addComponent(bus1); + partition1->addComponent(bus2); + partition1->addComponent(load1); + partition1->addComponent(busInterface); + + partition2->addComponent(dg3); + partition2->addComponent(dg4); + partition2->addComponent(l2); + partition2->addComponent(bus3); + partition2->addComponent(bus4); + partition2->addComponent(l3); + partition2->addComponent(load2); + + partition1->allocate(); + partition2->allocate(); + + std::vector y; + std::vector yp; + + for (size_t i = 0; i < vec_size_total; i++) + { + y.push_back(static_cast(i + 1)); + yp.push_back(static_cast(i + 1)); + } + + // Distribute externals to partition 1 + for (size_t i = 0; i < partition1->getExternSize(); i++) + { + partition1->getExternalDataY()[i] = y[partition1->getExternalIndices()[i]]; + partition1->getExternalDataYP()[i] = yp[partition1->getExternalIndices()[i]]; + } + + // Distribute externals to partition 2 + for (size_t i = 0; i < partition2->getExternSize(); i++) + { + partition2->getExternalDataY()[i] = y[partition2->getExternalIndices()[i]]; + partition2->getExternalDataYP()[i] = yp[partition2->getExternalIndices()[i]]; + } + + // Distribute internals to partition 1 + for (size_t i = 0; i < partition1->getInternalSize(); i++) + { + partition1->y()[i] = y[partition1->getNodeConnection(i)]; + partition1->yp()[i] = yp[partition1->getNodeConnection(i)]; + } + + // Distribute internals to partition 2 + for (size_t i = 0; i < partition2->getInternalSize(); i++) + { + partition2->y()[i] = y[partition2->getNodeConnection(i)]; + partition2->yp()[i] = yp[partition2->getNodeConnection(i)]; + } + + // Evaluate Residuals for each partition + partition1->evaluateResidual(); + partition2->evaluateResidual(); + + auto printTitle = [](std::string msg) -> void + { + std::cout << "\n------------- " << msg << " -----------" << std::endl; + printf("%-10s ---------- %10s\n", "Res Values", "Comp. Index"); + }; + + // Print Residuals from partition 1 + printTitle("Partition 1"); + for (size_t i = 0; i < partition1->getInternalSize(); i++) + { + auto com_index = partition1->getNodeConnection(static_cast(i)); + printf("%-10.5g ----------%zu %10zu\n", partition1->getResidual()[i], i, com_index); + } + + // Print Residuals from partition 2 + printTitle("Partition 2"); + for (size_t i = 0; i < partition2->getInternalSize(); i++) + { + auto com_index = partition2->getNodeConnection(static_cast(i)); + printf("%-10.5g ----------%zu %10zu\n", partition2->getResidual()[i], i, com_index); + } + + // sysmodel->addComponent(dg1); + // sysmodel->addComponent(dg2); + // sysmodel->addComponent(dg3); + // sysmodel->addComponent(dg4); + // sysmodel->addComponent(l1); + // sysmodel->addComponent(l2); + // sysmodel->addComponent(l3); + // sysmodel->addComponent(bus1); + // sysmodel->addComponent(bus2); + // sysmodel->addComponent(bus3); + // sysmodel->addComponent(bus4); + // sysmodel->addComponent(load1); + // sysmodel->addComponent(load2); + + // sysmodel->allocate(vec_size_total); + + // for (size_t i = 0; i < vec_size_total; i++) + // { + // sysmodel->y()[i] = y[i]; + // sysmodel->yp()[i] = yp[i]; + // } + + // sysmodel->evaluateResidual(); + + // printTitle("Reference Solution"); + // for (size_t i = 0; i < vec_size_total; i++) + // { + // printf("%-10.5g ---------- %10zu\n", sysmodel->getResidual()[i], i); + // } + + delete partition1; + delete partition2; + delete sysmodel; + + return 0; +} \ No newline at end of file From 9dbf8b6cea08960057ec5d0e3d58262e9c51ebd5 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Mon, 15 Jun 2026 01:45:13 +0000 Subject: [PATCH 08/34] Updated bus partition interface to work with new SubsystemModel --- .../BusPartitionInterface.cpp | 55 ++++++------------- .../BusPartitionInterface.hpp | 1 + 2 files changed, 18 insertions(+), 38 deletions(-) diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp index e275c6b39..2e04e558d 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp @@ -1,6 +1,7 @@ #include "BusPartitionInterface.hpp" +#include #include #include #include @@ -28,11 +29,15 @@ namespace GridKit BusPartitionInterface::BusPartitionInterface(CircuitComponent& component, IdxT bus_i, IdxT bus_j, IdxT id) : component_(component) { - size_ = 2; - n_intern_ = 0; - n_extern_ = 2; - extern_indices_ = {0, 1}; - idc_ = id; + size_ = component.size(); + n_intern_ = 0; + n_extern_ = static_cast(component.size()); + idc_ = id; + + for (IdxT i = 0; i < size_; i++) + { + extern_indices_.insert(i); + } bus_i_ = bus_i; bus_j_ = bus_j; @@ -53,14 +58,10 @@ namespace GridKit yp_.resize(static_cast(size_)); f_.resize(static_cast(size_)); - size_t interface_extern_size = static_cast(component_.size() - size_); - interface_partition_externals_.resize(interface_extern_size); - external_data_y_.resize(interface_extern_size, 0); - external_data_yp_.resize(interface_extern_size, 0); + std::fill(f_.begin(), f_.end(), 0); component_.allocate(); - size_t counter = 0; for (size_t i = 0; i < static_cast(component_.size()); i++) { if (bus_i_ == component_.getNodeConnection(static_cast(i))) @@ -71,16 +72,10 @@ namespace GridKit { bus_port_j_ = i; } - else - { - interface_partition_externals_[counter] = component_.getNodeConnection(static_cast(i)); - counter++; - } + IdxT global_idx = component_.getNodeConnection(static_cast(i)); + this->setExternalConnectionNodes(static_cast(i), global_idx); } - this->setExternalConnectionNodes(0, bus_i_); - this->setExternalConnectionNodes(1, bus_j_); - return 0; } @@ -108,31 +103,15 @@ namespace GridKit template int BusPartitionInterface::evaluateResidual() { - auto& y = component_.y(); - auto& yp = component_.yp(); - - y[bus_port_i_] = y_[0]; - y[bus_port_j_] = y_[1]; - - yp[bus_port_i_] = yp_[0]; - yp[bus_port_j_] = yp_[1]; - - size_t counter = 0; - for (size_t i = 0; i < static_cast(component_.size()); i++) - { - if (bus_port_i_ != i && bus_port_j_ != i) - { - y[i] = external_data_y_[counter]; - counter++; - } - } + std::copy(y_.begin(), y_.end(), component_.y().begin()); + std::copy(yp_.begin(), yp_.end(), component_.yp().begin()); component_.evaluateResidual(); auto& f = component_.getResidual(); - f_[0] = f[bus_port_i_]; - f_[1] = f[bus_port_j_]; + f_[bus_port_i_] = f[bus_port_i_]; + f_[bus_port_j_] = f[bus_port_j_]; return 0; } diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp index 0c8b2e902..1b1d9e4bd 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp @@ -5,6 +5,7 @@ #include #include + #include "GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp" namespace GridKit From 1a5a75b30c0432ad99a5d8aae9cf292c15008bcc Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Mon, 15 Jun 2026 01:47:12 +0000 Subject: [PATCH 09/34] Work in progress cosimulation implementation: in rought shape --- .../Solver/Dynamic/MultiStageCosimulation.cpp | 138 +++++++++++++----- .../Solver/Dynamic/MultiStageCosimulation.hpp | 70 +++++++-- 2 files changed, 161 insertions(+), 47 deletions(-) diff --git a/GridKit/Solver/Dynamic/MultiStageCosimulation.cpp b/GridKit/Solver/Dynamic/MultiStageCosimulation.cpp index 390eb8d03..9ce53ab3c 100644 --- a/GridKit/Solver/Dynamic/MultiStageCosimulation.cpp +++ b/GridKit/Solver/Dynamic/MultiStageCosimulation.cpp @@ -5,52 +5,99 @@ #include #include +#include #include +#include "GridKit/Solver/Dynamic/Interpolation.hpp" +#include "GridKit/Solver/Dynamic/Rosenbrock.hpp" + namespace Integrator { + template + MultiStageCosimulation::MultiStageCosimulation( + std::vector partitions, + std::size_t num_stages, + MemorySpace memspace) + : num_partitions_(partitions.size()), + num_stages_(num_stages), + memspace_(memspace), + partitions_(std::move(partitions)) + { + if (num_partitions_ == 0) + { + throw std::invalid_argument("MultiStageCosimulation requires at least one partition."); + } + + if (num_stages_ == 0) + { + throw std::invalid_argument("MultiStageCosimulation requires at least one stage."); + } + + for (auto* partition : partitions_) + { + if (partition == nullptr) + { + throw std::invalid_argument("Partition pointer cannot be null."); + } + } + } + // TODO: Complete implementation template int MultiStageCosimulation::allocate() { + num_partitions_ = partitions_.size(); + + x0_local_.resize(num_partitions_); + coupling_mat_.resize(num_partitions_); + linear_workspaces_.resize(num_partitions_); + lin_solver_.resize(num_partitions_); + solvers_.resize(num_partitions_); for (size_t p = 0; p < num_partitions_; ++p) { auto* part = partitions_[p]; + assert(part != nullptr); + + const IdxT num_states = part->getStateSize(); + const IdxT num_coupling = part->getCouplingSize(); - int num_coupling = part->getCouplingSize(); - int num_states = part->getStateSize(); + x0_local_[p] = std::make_unique(num_states); + x0_local_[p]->allocate(memspace_); - x0_local_[p] = State(num_states); - coupling_mat_[p] = State(num_coupling, num_stages_); + coupling_mat_[p] = std::make_unique(num_coupling); + coupling_mat_[p]->allocate(memspace_); - x0_local_[p].allocate(memspace_); - coupling_mat_[p].allocate(memspace_); + linear_workspaces_[p] = std::make_unique(); + + lin_solver_[p] = std::make_unique( + linear_workspaces_[p].get(), + "klu", + "klu", + "klu"); + + lin_solver_[p]->initialize(); + + solvers_[p] = std::make_unique( + Rosenbrock::Tableau::rodas5p(), + part, + lin_solver_[p].get(), + &vector_handler_); + + solvers_[p]->allocate(); } return 0; } template - int MultiStageCosimulation::distributeLocal(const State& global_y) + int MultiStageCosimulation::distributeLocal(const State& global_y, PartitionEvaluator* partition) { + auto& internal = partition->getInternalIndecies(); + size_t n = partition->size(); - auto* global_data = global_y.getData(memspace_); - - for (size_t p = 0; p < num_partitions_; ++p) - { - auto* part = partitions_[p]; - auto& internal = part->getInternalIndecies(); // TODO: add this function to partition evaluate - size_t n = part->size(); - - auto* local_data = x0_local_[p].getData(memspace_); - - for (size_t i = 0; i < n; ++i) - { - local_data[i] = global_data[internal[i]]; - } - } + matrix_handler_.matvec(); return 0; } @@ -87,32 +134,53 @@ namespace Integrator // TODO: Complete implementation template - int MultiStageCosimulation::partitionSolve() + int MultiStageCosimulation::partitionStageSolve(int stage, double t0, double dt) { - std::vector output_time = output_times; + std::vector out_times; - for (size_t i = 0; i < max_iterations_; i++) + for (size_t iter = 0; iter < max_iterations_; iter++) { - for (auto* partitionEvaluator : partitions_) + for (size_t part = 0; part < num_partitions_; part++) { - // TODO: add a coupling function to the partition - partitionEvaluator->addForcing(); + auto* partitionEvaluator = partitions_[part]; + auto* partition_solver = solvers_[part]; - if (i + 1 < max_iterations_) + if (stage == 0 && iter == 0) { - solver.integrate({t0}, partition_solution_.getData(stage)); + distributeLocal(y_, partitionEvaluator); } - else + + auto& coupling_stage_values = coupling_mat_[part]; + + GridKit::LagrangeInterpolant interp(coupling_stage_values, t0, dt); + partitionEvaluator->addForcing(interp); + + for (size_t i = 0; i < num_partitions_; i++) { - solver.integrate(output_time, partition_solution_); + partition_solution_[i]->setToZero(memspace_); } - } - updateCoupling(stage + 1) + int counter = 1; + + auto sol_out = [&](double tt, ReSolve::vector::Vector yp) -> void + { + auto* internal_csr = partition_internal_csr_[part].get(); + auto* internal_sol = partition_solution_[counter].get(); + + double alpha = 1.0; + double beta = 1.0; + + matrix_handler_.matvec(internal_csr, &yp, internal_sol, &alpha, &beta, memspace_); + + counter++; + }; + + partition_solver->integrate(out_times, stepController_, params_, sol_out); + } - if (stage == 0) + if (stage == 0) { break; } diff --git a/GridKit/Solver/Dynamic/MultiStageCosimulation.hpp b/GridKit/Solver/Dynamic/MultiStageCosimulation.hpp index ddc3ceb6a..ab6aabf08 100644 --- a/GridKit/Solver/Dynamic/MultiStageCosimulation.hpp +++ b/GridKit/Solver/Dynamic/MultiStageCosimulation.hpp @@ -11,15 +11,18 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include +#include namespace Integrator { @@ -31,28 +34,41 @@ namespace Integrator using RealT = typename GridKit::ScalarTraits::RealT; using Rosenbrock = Integrator::Rosenbrock; using PartitionEvaluator = GridKit::Model::PartitionEvaluator; + using MemorySpace = ReSolve::memory::MemorySpace; public: + MultiStageCosimulation(std::vector partitions, + size_t num_stages = 2, + size_t max_iterations = 2, + MemorySpace memspace = MemorySpace::HOST); + int initializeSimulation(RealT t0); int runSimulation(RealT tn, IdxT nout, std::optional> step_callback = {}); - int partitionSolve(); + int partitionStageSolve(int, double, double); - int timestepper(const std::vector& out_times, - std::optional> out_cb = {}); + int timestepper(const std::vector&, + std::optional>); - int distributeLocal(const State& global_y); + int distributeLocal(const State&); - int distributeCoupling(const State& global_y, int stage); + int distributeCoupling(const State&, int); int allocate(); private: + /** + * @brief + * + */ + std::vector> linear_workspaces_; + /** * @brief initial time */ - RealT t0_; + RealT t0_; + /** * @brief Maximum number of iterations per stage */ @@ -70,6 +86,22 @@ namespace Integrator */ size_t num_stages_; + /** + * + * @brief Number of stages used by the method + */ + size_t num_states_; + + /** + * + * @brief The global state of the system + */ + State y_; + + Rosenbrock::Parameters params_; + + Integrator::AdaptiveStep stepController_; + /** * * @brief Memory space used @@ -78,11 +110,18 @@ namespace Integrator /** * - * @brief Handles for linear algebra operations + * @brief Handles vector operations * */ ReSolve::VectorHandler vector_handler_; + /** + * + * @brief Handles matrix linear algebra operations + * + */ + ReSolve::MatrixHandler matrix_handler_; + /** * * @brief linear solver for the sub-integrator @@ -95,28 +134,35 @@ namespace Integrator * @brief Contains vectors of initial conditions for every step * */ - std::vector x0_local_; + std::vector> x0_local_; /** * * @brief Vectors of coupling matrices for each partition * */ - std::vector coupling_mat_; + std::vector>> coupling_mat_; /** * - * @brief Vector of stages + * @brief partition solution multi-dimensional vectors + * + */ + std::vector> partition_solution_; + + /** + * + * @brief partition solution multi-dimensional vectors * */ - State stages_; + std::vector partition_external_csr_; /** * * @brief partition solution multi-dimensional vectors * */ - State partition_solution_; + std::vector> partition_internal_csr_; /** * From a4b1c71a3a36f7c0a710b3bd935d405e68f383e8 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Mon, 15 Jun 2026 05:56:14 +0000 Subject: [PATCH 10/34] Cleaned up code in subsystem and made the partition microgrid test example more rebust --- .../Model/PowerElectronics/SubsystemModel.hpp | 20 +--- .../Partition/PartitionMicrogrid.cpp | 97 ++++++++++++------- 2 files changed, 69 insertions(+), 48 deletions(-) diff --git a/GridKit/Model/PowerElectronics/SubsystemModel.hpp b/GridKit/Model/PowerElectronics/SubsystemModel.hpp index af3d9dc9f..4db68eddd 100644 --- a/GridKit/Model/PowerElectronics/SubsystemModel.hpp +++ b/GridKit/Model/PowerElectronics/SubsystemModel.hpp @@ -82,11 +82,6 @@ namespace GridKit int allocate() override { - // Allocate all components - size_ = 0; - n_extern_ = 0; - n_intern_ = 0; - size_t counter = 0; // First pass: Map global component indices to local subsystem indices. @@ -102,7 +97,6 @@ namespace GridKit if (index != neg1_) { internal_map_[index] = counter; - n_intern_++; counter++; } } @@ -119,19 +113,17 @@ namespace GridKit counter++; internal_map_[index2] = counter; counter++; - n_intern_ += 2; } } + // If this subsystem contains the reference generator, add the rotor motor as an internal if (refframe_index_ != neg1_) { internal_map_[refframe_index_] = counter; - n_intern_++; counter++; } - // Second pass: Identify variables required by this partition but owned by - // another partition. + // Second pass: Identify variables required by this partition but owned by another partition. for (const auto& component : components_) { for (IdxT i = 0; i < component->getExternSize(); i++) @@ -141,14 +133,14 @@ namespace GridKit if (internal_map_.count(index) < 1 && external_map_.count(index) < 1 && index != neg1_) { external_map_[index] = counter; - counter++; - n_extern_++; } } } - size_ = n_intern_ + n_extern_; + n_intern_ = internal_map_.size(); + n_extern_ = external_map_.size(); + size_ = n_intern_ + n_extern_; this->mapGlobalToLocal(); @@ -275,8 +267,6 @@ namespace GridKit /** * @brief Creates the system Jacobian representing \alpha dF/dy' + dF/dy * - * Updates the CSR Jacobian values using the per-component mappings - * computed during allocate(). * * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable */ diff --git a/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp b/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp index 4a961caa8..8bc6b00c0 100644 --- a/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp +++ b/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp @@ -1,3 +1,4 @@ +#include #include #define _USE_MATH_DEFINES @@ -288,8 +289,23 @@ int main() partition2->addComponent(l3); partition2->addComponent(load2); + sysmodel->addComponent(new GridKit::DistributedGenerator(*dg1)); + sysmodel->addComponent(new GridKit::DistributedGenerator(*dg2)); + sysmodel->addComponent(new GridKit::DistributedGenerator(*dg3)); + sysmodel->addComponent(new GridKit::DistributedGenerator(*dg4)); + sysmodel->addComponent(new GridKit::MicrogridLine(*l1)); + sysmodel->addComponent(new GridKit::MicrogridLine(*l2)); + sysmodel->addComponent(new GridKit::MicrogridLine(*l3)); + sysmodel->addComponent(new GridKit::MicrogridBusDQ(*bus1)); + sysmodel->addComponent(new GridKit::MicrogridBusDQ(*bus2)); + sysmodel->addComponent(new GridKit::MicrogridBusDQ(*bus3)); + sysmodel->addComponent(new GridKit::MicrogridBusDQ(*bus4)); + sysmodel->addComponent(new GridKit::MicrogridLoad(*load1)); + sysmodel->addComponent(new GridKit::MicrogridLoad(*load2)); + partition1->allocate(); partition2->allocate(); + sysmodel->allocate(vec_size_total); std::vector y; std::vector yp; @@ -334,8 +350,8 @@ int main() auto printTitle = [](std::string msg) -> void { - std::cout << "\n------------- " << msg << " -----------" << std::endl; - printf("%-10s ---------- %10s\n", "Res Values", "Comp. Index"); + std::cout << "\n--------------- " << msg << " -------------" << std::endl; + printf("%-12s ---------- %12s\n", "Res Values", "Comp. Index"); }; // Print Residuals from partition 1 @@ -343,7 +359,7 @@ int main() for (size_t i = 0; i < partition1->getInternalSize(); i++) { auto com_index = partition1->getNodeConnection(static_cast(i)); - printf("%-10.5g ----------%zu %10zu\n", partition1->getResidual()[i], i, com_index); + printf("%-12.5g ---------- %7zu\n", partition1->getResidual()[i], com_index); } // Print Residuals from partition 2 @@ -351,38 +367,53 @@ int main() for (size_t i = 0; i < partition2->getInternalSize(); i++) { auto com_index = partition2->getNodeConnection(static_cast(i)); - printf("%-10.5g ----------%zu %10zu\n", partition2->getResidual()[i], i, com_index); + printf("%-12.5g ---------- %7zu\n", partition2->getResidual()[i], com_index); + } + + for (size_t i = 0; i < vec_size_total; i++) + { + sysmodel->y()[i] = y[i]; + sysmodel->yp()[i] = yp[i]; + } + + sysmodel->evaluateResidual(); + + printTitle("Reference Solution"); + for (size_t i = 0; i < vec_size_total; i++) + { + printf("%-12.5g ---------- %7zu\n", sysmodel->getResidual()[i], i); + } + + std::vector f(vec_size_total, 0.0); + std::vector error(vec_size_total, 1.0); + + // Get internal residuals from partition 1 + for (size_t i = 0; i < partition1->getInternalSize(); i++) + { + f[partition1->getNodeConnection(i)] = partition1->getResidual()[i]; + } + + // Get internal residuals from partition 2 + for (size_t i = 0; i < partition2->getInternalSize(); i++) + { + f[partition2->getNodeConnection(i)] = partition2->getResidual()[i]; + } + + for (size_t i = 0; i < vec_size_total; i++) + { + error[i] = sysmodel->getResidual()[i] - f[i]; + } + + double max_error = 0; + for (size_t i = 0; i < vec_size_total; i++) + { + if (max_error < std::abs(error[i])) + { + max_error = std::abs(error[i]); + } } - // sysmodel->addComponent(dg1); - // sysmodel->addComponent(dg2); - // sysmodel->addComponent(dg3); - // sysmodel->addComponent(dg4); - // sysmodel->addComponent(l1); - // sysmodel->addComponent(l2); - // sysmodel->addComponent(l3); - // sysmodel->addComponent(bus1); - // sysmodel->addComponent(bus2); - // sysmodel->addComponent(bus3); - // sysmodel->addComponent(bus4); - // sysmodel->addComponent(load1); - // sysmodel->addComponent(load2); - - // sysmodel->allocate(vec_size_total); - - // for (size_t i = 0; i < vec_size_total; i++) - // { - // sysmodel->y()[i] = y[i]; - // sysmodel->yp()[i] = yp[i]; - // } - - // sysmodel->evaluateResidual(); - - // printTitle("Reference Solution"); - // for (size_t i = 0; i < vec_size_total; i++) - // { - // printf("%-10.5g ---------- %10zu\n", sysmodel->getResidual()[i], i); - // } + std::cout << "\nMax Error of Reference and Partition Evaluation: " << max_error << std::endl; delete partition1; delete partition2; From 70bcfa8386aa0b5678ae6c2b1a3e2dfa507a6bf1 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Wed, 24 Jun 2026 15:25:27 +0000 Subject: [PATCH 11/34] First attempt at arbitrary partitioning --- .../Partition/PartitionScaleMicrogrid.cpp | 392 ++++++++++++++++++ 1 file changed, 392 insertions(+) create mode 100644 examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp diff --git a/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp b/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp new file mode 100644 index 000000000..178ad0a47 --- /dev/null +++ b/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp @@ -0,0 +1,392 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using index_type = size_t; +using real_type = double; + +int printMicrogridSystems(index_type N_size); + +/** + * @brief Run Scale Microgrid for a specific N given by the user. + * + * @param[in] argc should be 1 if no N given, 2 if N given + * @param[in] argv can contain the N value (argv[1]) + * @return int + */ +int main(int argc, char const* argv[]) +{ + // Default value + index_type N_size = 2; + + // Parse command line arguments if provided + if (argc > 1) + { + try + { + N_size = static_cast(std::stoi(argv[1])); + } + catch (const std::exception& e) + { + std::cerr << "Error parsing grid size argument: " << e.what() << std::endl; + std::cerr << "Using default grid size = " << N_size << std::endl; + } + } + + return printMicrogridSystems(N_size); +} + +/** + * @brief Tests network of distributed generators. + * + * @param[in] N_size - The number of DG line load cobinations to generate for scale + * @return int returns 0 if successful, >0 otherwise + */ +int printMicrogridSystems(index_type N_size) +{ + using namespace GridKit; + + const size_t num_ibrs = 2 * N_size; + const size_t num_partitions = 4; + + assert(num_partitions <= num_ibrs); + + bool use_jac = true; + + real_type rel_tol = 1e-5; + real_type abs_tol = 1e-5; + + // Create circuit model + auto* sys_model = new PowerElectronicsModel(rel_tol, + abs_tol, + use_jac, + 2000); + + // Ensure minimum size requirement + if (N_size < 1) + { + std::cout << "N_size must be at least 1.\n"; + 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. + GridKit::DistributedGeneratorParameters 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; + + GridKit::DistributedGeneratorParameters 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; + + 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 * 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; + } + + using SignalNode = GridKit::PowerElectronics::SignalNode; + using Bus = GridKit::PowerElectronics::MicrogridBus; + using BusDQ = MicrogridBusDQ; + using Generator = DistributedGenerator; + using Line = MicrogridLine; + using Load = MicrogridLoad; + + std::vector buses(num_ibrs, nullptr); + std::vector busesDQ(num_ibrs, nullptr); + std::vector generators(num_ibrs, nullptr); + std::vector lines(num_ibrs, nullptr); + std::vector loads(num_ibrs, nullptr); + + SignalNode dg_signal; + sys_model->addNode(&dg_signal); + + for (size_t i = 0; i < 2 * N_size; i++) + { + buses[i] = new Bus(); + sys_model->addNode(buses[i]); + } + + // Create the reference DG + auto* dg_ref = new DistributedGenerator(0, + DGParams_list[0], + true, + &dg_signal, + buses[0]); + sys_model->addComponent(dg_ref); + + generators[0] = 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]); + + generators[i] = dg; + 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], + buses[i + 1]); + lines[i + 1] = line_model; + 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]); + loads[2 * i] = load_model; + 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]); + + busesDQ[i] = virDQbus_model; + sys_model->addComponent(virDQbus_model); + } + + sys_model->allocate(); + + std::vector y; + std::vector yp; + + for (size_t i = 0; i < sys_model->size(); i++) + { + y.push_back(static_cast(i + 1)); + yp.push_back(static_cast(i + 1)); + } + + for (size_t i = 0; i < sys_model->size(); i++) + { + sys_model->y()[i] = y[i]; + sys_model->yp()[i] = yp[i]; + } + + sys_model->evaluateResidual(); + std::vector f_sysmodel = sys_model->getResidual(); + + std::vector*> subsystems(num_partitions); + + // Partition the system + index_type q = (num_ibrs) / num_partitions; + index_type r = (num_ibrs) % num_partitions; + index_type index = 0; + for (index_type j = 0; j < num_partitions; j++) + { + auto* partition = new SubsystemModel(false); + + // add Reference rotor to the first partition + if (j == 0) + { + partition->addNode(&dg_signal); + } + + std::cout << "Partition " << j << std::endl; + + index_type part_size = q + (j < r ? 1 : 0); + index_type end = std::min(index + part_size, num_ibrs); + + // Add all components belonging to this partition + for (; index < end; ++index) + { + partition->addComponent(generators[index]); + std::cout << "Comp Gen" << index << std::endl; + partition->addComponent(busesDQ[index]); + std::cout << "Comp BDQ" << index << std::endl; + + if (loads[index] != nullptr) + { + partition->addComponent(loads[index]); + std::cout << "Comp Load" << index << std::endl; + } + + if (lines[index] != nullptr) + { + partition->addComponent(lines[index]); + std::cout << "Comp Line" << index << std::endl; + } + + std::cout << "Comp Bus " << index << std::endl; + + partition->addNode(buses[index]); + } + + // Add partition interface at a partition point + if (index < num_ibrs) + { + auto* linecopy = new GridKit::MicrogridLine(*lines[index]); + + auto* busInterface = new GridKit::BusPartitionInterface(*buses[index - 1], *linecopy, model_id++); + busInterface->allocate(); + + std::cout << "Interface " << "(" << index - 1 << ", " << index << ")" << std::endl; + + partition->addComponent(busInterface); + } + + subsystems[j] = partition; + } + + for (auto* partition : subsystems) + { + partition->toString(); + partition->allocate(); + } + + // Distribute externals to partition 1 + for (auto* partition : subsystems) + { + for (size_t i = 0; i < partition->getExternSize(); i++) + { + partition->getExternalDataY()[i] = y[partition->getExternalIndices()[i]]; + partition->getExternalDataYP()[i] = yp[partition->getExternalIndices()[i]]; + } + } + + for (auto* partition : subsystems) + { + for (size_t i = 0; i < partition->getInternalSize(); i++) + { + partition->y()[i] = y[partition->getNodeConnection(i)]; + partition->yp()[i] = yp[partition->getNodeConnection(i)]; + } + } + + for (auto* partition : subsystems) + { + partition->evaluateResidual(); + } + + std::vector f(sys_model->size(), 0.0); + std::vector error(sys_model->size(), 1.0); + + // Get internal residuals from partition 1 + for (auto* partition : subsystems) + { + for (size_t i = 0; i < partition->getInternalSize(); i++) + { + f[partition->getNodeConnection(i)] = partition->getResidual()[i]; + } + } + + for (size_t i = 0; i < sys_model->size(); i++) + { + error[i] = f_sysmodel[i] - f[i]; + std::cout << i << " " << error[i] << " ---------- " << i << std::endl; + } + + double max_error = 0; + for (size_t i = 0; i < sys_model->size(); i++) + { + if (max_error < std::abs(error[i])) + { + max_error = std::abs(error[i]); + } + } + + std::cout << "\nMax Error of Reference and Partition Evaluation: " << max_error << std::endl; + + return 0; +} From ef1bbd3ee27fc91c1c7b12e500f9422e9f29fddc Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Wed, 24 Jun 2026 19:05:53 +0000 Subject: [PATCH 12/34] Added microgrid with four partitions --- .../Partition/PartitionMicrogrid.cpp | 383 +++++++----------- 1 file changed, 136 insertions(+), 247 deletions(-) diff --git a/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp b/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp index 8bc6b00c0..f9e00c37b 100644 --- a/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp +++ b/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp @@ -1,10 +1,13 @@ #include #include +#include #define _USE_MATH_DEFINES #include #include +#include +#include #include #include #include @@ -12,6 +15,8 @@ #include #include #include +#include +#include int main() { @@ -22,6 +27,7 @@ int main() size_t max_step_number = 3000; bool use_jac = true; + // Create model auto* sysmodel = new GridKit::PowerElectronicsModel(rel_tol, abs_tol, use_jac, max_step_number); // Modeled after the problem in the paper @@ -80,274 +86,174 @@ int main() double rload2 = 2.0; double Lload2 = 1.0 / (2.0 * M_PI * 50.0); - // indexing sets - size_t Nsize = 2; - // DGs + - refframe Lines + Loads - size_t vec_size_internals = 13 * (2 * Nsize) - 1 + (2 + 4 * (Nsize - 1)) + 2 * Nsize; - // \omegaref + BusDQ - size_t vec_size_externals = 1 + 2 * (2 * Nsize); - size_t dqbus1 = vec_size_internals + 1; - size_t dqbus2 = vec_size_internals + 3; - size_t dqbus3 = vec_size_internals + 5; - size_t dqbus4 = vec_size_internals + 7; + using SignalNode = GridKit::PowerElectronics::SignalNode; + SignalNode dg_signal; - size_t vec_size_total = vec_size_internals + vec_size_externals; + sysmodel->addNode(&dg_signal); - size_t indexv = 0; + using Bus = GridKit::PowerElectronics::MicrogridBus; + Bus bus1; + Bus bus2; + Bus bus3; + Bus bus4; - // dg 1 - GridKit::DistributedGenerator* dg1 = new GridKit::DistributedGenerator(0, parms1, true); - // ref motor - dg1->setExternalConnectionNodes(0, vec_size_internals); - // outputs - dg1->setExternalConnectionNodes(1, dqbus1); - dg1->setExternalConnectionNodes(2, dqbus1 + 1); - //"grounding" of the difference - dg1->setExternalConnectionNodes(3, static_cast(-1)); - // internal connections - for (size_t i = 0; i < 12; i++) - { + sysmodel->addNode(&bus1); + sysmodel->addNode(&bus2); + sysmodel->addNode(&bus3); + sysmodel->addNode(&bus4); - dg1->setExternalConnectionNodes(4 + i, indexv + i); - } - indexv += 12; + // 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); - // ref motor - dg2->setExternalConnectionNodes(0, vec_size_internals); - // outputs - dg2->setExternalConnectionNodes(1, dqbus2); - dg2->setExternalConnectionNodes(2, dqbus2 + 1); - // internal connections - for (size_t i = 0; i < 13; i++) - { - - dg2->setExternalConnectionNodes(3 + i, indexv + i); - } - indexv += 13; + 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); - // ref motor - dg3->setExternalConnectionNodes(0, vec_size_internals); - // outputs - dg3->setExternalConnectionNodes(1, dqbus3); - dg3->setExternalConnectionNodes(2, dqbus3 + 1); - // internal connections - for (size_t i = 0; i < 13; i++) - { - - dg3->setExternalConnectionNodes(3 + i, indexv + i); - } - indexv += 13; + 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); - // ref motor - dg4->setExternalConnectionNodes(0, vec_size_internals); - // outputs - dg4->setExternalConnectionNodes(1, dqbus4); - dg4->setExternalConnectionNodes(2, dqbus4 + 1); - - // internal connections - for (size_t i = 0; i < 13; i++) - { - - dg4->setExternalConnectionNodes(3 + i, indexv + i); - } - indexv += 13; + 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); - // ref motor - l1->setExternalConnectionNodes(0, vec_size_internals); - // input connections - l1->setExternalConnectionNodes(1, dqbus1); - l1->setExternalConnectionNodes(2, dqbus1 + 1); - // output connections - l1->setExternalConnectionNodes(3, dqbus2); - l1->setExternalConnectionNodes(4, dqbus2 + 1); - // internal connections - for (size_t i = 0; i < 2; i++) - { - - l1->setExternalConnectionNodes(5 + i, indexv + i); - } - indexv += 2; + 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); - // ref motor - l2->setExternalConnectionNodes(0, vec_size_internals); - // input connections - l2->setExternalConnectionNodes(1, dqbus2); - l2->setExternalConnectionNodes(2, dqbus2 + 1); - // output connections - l2->setExternalConnectionNodes(3, dqbus3); - l2->setExternalConnectionNodes(4, dqbus3 + 1); - // internal connections - for (size_t i = 0; i < 2; i++) - { - - l2->setExternalConnectionNodes(5 + i, indexv + i); - } - indexv += 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); - // ref motor - l3->setExternalConnectionNodes(0, vec_size_internals); - // input connections - l3->setExternalConnectionNodes(1, dqbus3); - l3->setExternalConnectionNodes(2, dqbus3 + 1); - // output connections - l3->setExternalConnectionNodes(3, dqbus4); - l3->setExternalConnectionNodes(4, dqbus4 + 1); - // internal connections - for (size_t i = 0; i < 2; i++) - { - - l3->setExternalConnectionNodes(5 + i, indexv + i); - } - indexv += 2; + 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); - // ref motor - load1->setExternalConnectionNodes(0, vec_size_internals); - // input connections - load1->setExternalConnectionNodes(1, dqbus1); - load1->setExternalConnectionNodes(2, dqbus1 + 1); - // internal connections - for (size_t i = 0; i < 2; i++) - { - - load1->setExternalConnectionNodes(3 + i, indexv + i); - } - indexv += 2; + 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); - // ref motor - load2->setExternalConnectionNodes(0, vec_size_internals); - // input connections - load2->setExternalConnectionNodes(1, dqbus3); - load2->setExternalConnectionNodes(2, dqbus3 + 1); - // internal connections - for (size_t i = 0; i < 2; i++) - { - - load2->setExternalConnectionNodes(3 + i, indexv + i); - } - indexv += 2; + GridKit::MicrogridLoad* load2 = new GridKit::MicrogridLoad(8, rload2, Lload2, &dg_signal, &bus3); + sysmodel->addComponent(load2); // Virtual PQ Buses - GridKit::MicrogridBusDQ* bus1 = new GridKit::MicrogridBusDQ(9, RN); - - bus1->setExternalConnectionNodes(0, dqbus1); - bus1->setExternalConnectionNodes(1, dqbus1 + 1); + GridKit::MicrogridBusDQ* bus_para_1 = new GridKit::MicrogridBusDQ(9, RN, &bus1); + sysmodel->addComponent(bus_para_1); - GridKit::MicrogridBusDQ* bus2 = new GridKit::MicrogridBusDQ(10, RN); + GridKit::MicrogridBusDQ* bus_para_2 = new GridKit::MicrogridBusDQ(10, RN, &bus2); + sysmodel->addComponent(bus_para_2); - bus2->setExternalConnectionNodes(0, dqbus2); - bus2->setExternalConnectionNodes(1, dqbus2 + 1); + GridKit::MicrogridBusDQ* bus_para_3 = new GridKit::MicrogridBusDQ(11, RN, &bus3); + sysmodel->addComponent(bus_para_3); - GridKit::MicrogridBusDQ* bus3 = new GridKit::MicrogridBusDQ(11, RN); + GridKit::MicrogridBusDQ* bus_para_4 = new GridKit::MicrogridBusDQ(12, RN, &bus4); + sysmodel->addComponent(bus_para_4); - bus3->setExternalConnectionNodes(0, dqbus3); - bus3->setExternalConnectionNodes(1, dqbus3 + 1); + sysmodel->allocate(); - GridKit::MicrogridBusDQ* bus4 = new GridKit::MicrogridBusDQ(12, RN); + GridKit::SubsystemModel* partition1 = new GridKit::SubsystemModel(false); + GridKit::SubsystemModel* partition2 = new GridKit::SubsystemModel(false); + GridKit::SubsystemModel* partition3 = new GridKit::SubsystemModel(false); + GridKit::SubsystemModel* partition4 = new GridKit::SubsystemModel(false); - bus4->setExternalConnectionNodes(0, dqbus4); - bus4->setExternalConnectionNodes(1, dqbus4 + 1); + GridKit::MicrogridLine l1copy(*l1); + GridKit::MicrogridLine l2copy(*l2); + GridKit::MicrogridLine l3copy(*l3); + GridKit::BusPartitionInterface* busInterface1 = new GridKit::BusPartitionInterface(bus1, l1copy, 14); + GridKit::BusPartitionInterface* busInterface2 = new GridKit::BusPartitionInterface(bus2, l2copy, 15); + GridKit::BusPartitionInterface* busInterface3 = new GridKit::BusPartitionInterface(bus3, l3copy, 16); - GridKit::SubsystemModel* partition1 = new GridKit::SubsystemModel(vec_size_internals); - GridKit::SubsystemModel* partition2 = new GridKit::SubsystemModel(); - - GridKit::MicrogridLine comp3copy(*l2); - GridKit::BusPartitionInterface* busInterface = new GridKit::BusPartitionInterface(comp3copy, dqbus2, dqbus2 + 1, 14); + busInterface1->allocate(); + busInterface2->allocate(); + busInterface3->allocate(); + partition1->addNode(&dg_signal); partition1->addComponent(dg1); - partition1->addComponent(dg2); - partition1->addComponent(l1); - partition1->addComponent(bus1); - partition1->addComponent(bus2); + partition1->addComponent(bus_para_1); + partition1->addNode(&bus1); partition1->addComponent(load1); - partition1->addComponent(busInterface); - - partition2->addComponent(dg3); - partition2->addComponent(dg4); - partition2->addComponent(l2); - partition2->addComponent(bus3); - partition2->addComponent(bus4); - partition2->addComponent(l3); - partition2->addComponent(load2); - - sysmodel->addComponent(new GridKit::DistributedGenerator(*dg1)); - sysmodel->addComponent(new GridKit::DistributedGenerator(*dg2)); - sysmodel->addComponent(new GridKit::DistributedGenerator(*dg3)); - sysmodel->addComponent(new GridKit::DistributedGenerator(*dg4)); - sysmodel->addComponent(new GridKit::MicrogridLine(*l1)); - sysmodel->addComponent(new GridKit::MicrogridLine(*l2)); - sysmodel->addComponent(new GridKit::MicrogridLine(*l3)); - sysmodel->addComponent(new GridKit::MicrogridBusDQ(*bus1)); - sysmodel->addComponent(new GridKit::MicrogridBusDQ(*bus2)); - sysmodel->addComponent(new GridKit::MicrogridBusDQ(*bus3)); - sysmodel->addComponent(new GridKit::MicrogridBusDQ(*bus4)); - sysmodel->addComponent(new GridKit::MicrogridLoad(*load1)); - sysmodel->addComponent(new GridKit::MicrogridLoad(*load2)); - - partition1->allocate(); - partition2->allocate(); - sysmodel->allocate(vec_size_total); + partition1->addComponent(busInterface1); + + partition2->addComponent(dg2); + partition2->addComponent(l1); + partition2->addComponent(busInterface2); + partition2->addComponent(bus_para_2); + partition2->addNode(&bus2); + + partition3->addComponent(dg3); + partition3->addComponent(l2); + partition3->addComponent(busInterface3); + partition3->addComponent(load2); + partition3->addComponent(bus_para_3); + partition3->addNode(&bus3); + + partition4->addComponent(dg4); + partition4->addComponent(l3); + partition4->addComponent(bus_para_4); + partition4->addNode(&bus4); std::vector y; std::vector yp; - for (size_t i = 0; i < vec_size_total; i++) + for (size_t i = 0; i < sysmodel->size(); i++) { y.push_back(static_cast(i + 1)); yp.push_back(static_cast(i + 1)); } - // Distribute externals to partition 1 - for (size_t i = 0; i < partition1->getExternSize(); i++) + for (size_t i = 0; i < sysmodel->size(); i++) { - partition1->getExternalDataY()[i] = y[partition1->getExternalIndices()[i]]; - partition1->getExternalDataYP()[i] = yp[partition1->getExternalIndices()[i]]; + sysmodel->y()[i] = y[i]; + sysmodel->yp()[i] = yp[i]; } - // Distribute externals to partition 2 - for (size_t i = 0; i < partition2->getExternSize(); i++) + sysmodel->evaluateResidual(); + std::vector f_sysmodel = sysmodel->getResidual(); + + partition1->allocate(); + partition2->allocate(); + partition3->allocate(); + partition4->allocate(); + + std::vector*> partitions = {partition1, partition2, partition3, partition4}; + + // Distribute externals to partition 1 + for (auto* partition : partitions) { - partition2->getExternalDataY()[i] = y[partition2->getExternalIndices()[i]]; - partition2->getExternalDataYP()[i] = yp[partition2->getExternalIndices()[i]]; + for (size_t i = 0; i < partition->getExternSize(); i++) + { + partition->getExternalDataY()[i] = y[partition->getExternalIndices()[i]]; + partition->getExternalDataYP()[i] = yp[partition->getExternalIndices()[i]]; + } } - // Distribute internals to partition 1 - for (size_t i = 0; i < partition1->getInternalSize(); i++) + for (auto* partition : partitions) { - partition1->y()[i] = y[partition1->getNodeConnection(i)]; - partition1->yp()[i] = yp[partition1->getNodeConnection(i)]; + for (size_t i = 0; i < partition->getInternalSize(); i++) + { + partition->y()[i] = y[partition->getNodeConnection(i)]; + partition->yp()[i] = yp[partition->getNodeConnection(i)]; + } } - // Distribute internals to partition 2 - for (size_t i = 0; i < partition2->getInternalSize(); i++) + for (auto* partition : partitions) { - partition2->y()[i] = y[partition2->getNodeConnection(i)]; - partition2->yp()[i] = yp[partition2->getNodeConnection(i)]; + partition->evaluateResidual(); } - // Evaluate Residuals for each partition - partition1->evaluateResidual(); - partition2->evaluateResidual(); - auto printTitle = [](std::string msg) -> void { std::cout << "\n--------------- " << msg << " -------------" << std::endl; @@ -355,57 +261,42 @@ int main() }; // Print Residuals from partition 1 - printTitle("Partition 1"); - for (size_t i = 0; i < partition1->getInternalSize(); i++) - { - auto com_index = partition1->getNodeConnection(static_cast(i)); - printf("%-12.5g ---------- %7zu\n", partition1->getResidual()[i], com_index); - } - - // Print Residuals from partition 2 - printTitle("Partition 2"); - for (size_t i = 0; i < partition2->getInternalSize(); i++) - { - auto com_index = partition2->getNodeConnection(static_cast(i)); - printf("%-12.5g ---------- %7zu\n", partition2->getResidual()[i], com_index); - } - - for (size_t i = 0; i < vec_size_total; i++) + int counter = 1; + for (auto* partition : partitions) { - sysmodel->y()[i] = y[i]; - sysmodel->yp()[i] = yp[i]; + printTitle("Partition " + std::to_string(counter++)); + for (size_t i = 0; i < partition->getInternalSize(); i++) + { + auto com_index = partition->getNodeConnection(static_cast(i)); + printf("%-12.5g ---------- %7zu\n", partition->getResidual()[i], com_index); + } } - sysmodel->evaluateResidual(); - printTitle("Reference Solution"); - for (size_t i = 0; i < vec_size_total; i++) + for (size_t i = 0; i < sysmodel->size(); i++) { printf("%-12.5g ---------- %7zu\n", sysmodel->getResidual()[i], i); } - std::vector f(vec_size_total, 0.0); - std::vector error(vec_size_total, 1.0); + std::vector f(sysmodel->size(), 0.0); + std::vector error(sysmodel->size(), 1.0); // Get internal residuals from partition 1 - for (size_t i = 0; i < partition1->getInternalSize(); i++) - { - f[partition1->getNodeConnection(i)] = partition1->getResidual()[i]; - } - - // Get internal residuals from partition 2 - for (size_t i = 0; i < partition2->getInternalSize(); i++) + for (auto* partition : partitions) { - f[partition2->getNodeConnection(i)] = partition2->getResidual()[i]; + for (size_t i = 0; i < partition->getInternalSize(); i++) + { + f[partition->getNodeConnection(i)] = partition->getResidual()[i]; + } } - for (size_t i = 0; i < vec_size_total; i++) + for (size_t i = 0; i < sysmodel->size(); i++) { - error[i] = sysmodel->getResidual()[i] - f[i]; + error[i] = f_sysmodel[i] - f[i]; } double max_error = 0; - for (size_t i = 0; i < vec_size_total; i++) + for (size_t i = 0; i < sysmodel->size(); i++) { if (max_error < std::abs(error[i])) { @@ -415,8 +306,6 @@ int main() std::cout << "\nMax Error of Reference and Partition Evaluation: " << max_error << std::endl; - delete partition1; - delete partition2; delete sysmodel; return 0; From a98fb800a4fa07c19fab02c81e2eacc3c952acf6 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Wed, 24 Jun 2026 20:09:34 +0000 Subject: [PATCH 13/34] first version of subsystem --- .../Model/PowerElectronics/SubsystemModel.hpp | 264 ++++++++++++------ 1 file changed, 177 insertions(+), 87 deletions(-) diff --git a/GridKit/Model/PowerElectronics/SubsystemModel.hpp b/GridKit/Model/PowerElectronics/SubsystemModel.hpp index 4db68eddd..f2bfeb2dd 100644 --- a/GridKit/Model/PowerElectronics/SubsystemModel.hpp +++ b/GridKit/Model/PowerElectronics/SubsystemModel.hpp @@ -3,17 +3,16 @@ #pragma once #include +#include #include #include #include +#include #include #include -#include #include -#include "GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.hpp" - namespace GridKit { template @@ -23,20 +22,23 @@ namespace GridKit using MatrixT = typename CircuitComponent::MatrixT; using CsrMatrixT = typename CircuitComponent::CsrMatrixT; using component_type = CircuitComponent; - using node_type = CircuitNode; + using node_type = PowerElectronics::NodeBase; using CircuitComponent::size_; - using CircuitComponent::n_extern_; 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::jac_; + using CircuitComponent::f_int_; using CircuitComponent::rel_tol_; using CircuitComponent::abs_tol_; + using CircuitComponent::extern_indices_; public: /** @@ -44,7 +46,8 @@ namespace GridKit * * @post System model parameters set as default */ - SubsystemModel(IdxT refframe_index = neg1_) + + SubsystemModel(bool root = true) { // Set system model parameters as default rel_tol_ = 1e-4; @@ -52,7 +55,7 @@ namespace GridKit this->max_steps_ = 2000; // By default don't use the jacobian use_jac_ = false; - refframe_index_ = refframe_index; + root_ = root; } virtual ~SubsystemModel() @@ -82,89 +85,59 @@ namespace GridKit int allocate() override { - size_t counter = 0; - - // First pass: Map global component indices to local subsystem indices. - for (const auto& component : components_) - { - component->allocate(); - - for (IdxT i = component->getExternSize(); i < component->size(); i++) - { - - IdxT index = component->getNodeConnection(i); - - if (index != neg1_) - { - internal_map_[index] = counter; - counter++; - } - } - // TODO : To be removed once MicrogridBusDQ owns its internals - auto* comp = dynamic_cast*>(component); + this->createGlobalToInternalMap(); - if (comp != nullptr) - { - IdxT index1 = component->getNodeConnection(0); - IdxT index2 = component->getNodeConnection(1); - - internal_map_[index1] = counter; - counter++; - internal_map_[index2] = counter; - counter++; - } - } - - // If this subsystem contains the reference generator, add the rotor motor as an internal - if (refframe_index_ != neg1_) - { - internal_map_[refframe_index_] = counter; - counter++; - } - - // Second pass: Identify variables required by this partition but owned by another partition. - for (const auto& component : components_) - { - for (IdxT i = 0; i < component->getExternSize(); i++) - { - IdxT index = component->getNodeConnection(i); - - if (internal_map_.count(index) < 1 && external_map_.count(index) < 1 && index != neg1_) - { - external_map_[index] = counter; - counter++; - } - } - } + this->mapGlobalToLocal(); n_intern_ = internal_map_.size(); n_extern_ = external_map_.size(); size_ = n_intern_ + n_extern_; - this->mapGlobalToLocal(); + CircuitComponent::allocate(); - // Allocate subsystem vectors. y_.resize(n_intern_); yp_.resize(n_intern_); f_.resize(n_intern_); - // Allocate vectors associated with external coupling variables. + // Allocate subsystem vectors. y_ext_.resize(n_extern_); yp_ext_.resize(n_extern_); f_ext_.resize(n_extern_); external_indices_.resize(n_extern_); // Store the mapping from local subsystem indices back to their global system indices - for (const auto& [global_idx, local_idx] : internal_map_) + for (const auto [global_idx, local_idx] : internal_map_) { this->setExternalConnectionNodes(local_idx, global_idx); } // Store the global indices of all external coupling variables. - for (const auto& [global_idx, local_idx] : external_map_) + for (const auto [global_idx, local_idx] : external_map_) { external_indices_[local_idx - n_intern_] = global_idx; + extern_indices_.insert(local_idx); + this->setExternalConnectionNodes(local_idx, global_idx); + } + + { + size_t component_internal_idx = 0; + for (component_type* comp : components_) + { + + comp->setInternalPointer(&y_[component_internal_idx]); + comp->setInternalDerivativePointer(&yp_[component_internal_idx]); + comp->setInternalResidualPointer(&f_[component_internal_idx]); + + const auto& external_indices = comp->getExternIndices(); + for (size_t i = 0; i < comp->size(); i++) + { + if (!external_indices.contains(i)) + { + component_internal_idx++; + } + } + } } return 0; @@ -196,13 +169,13 @@ namespace GridKit */ int distributeVectors() { - for (const auto& component : components_) + for (component_type* component : components_) { - IdxT size = component->size(); - std::vector& y = component->y(); - std::vector& yp = component->yp(); + std::vector& y = component->y(); + std::vector& yp = component->yp(); + const std::set& externals = component->getExternIndices(); - for (IdxT j = 0; j < size; ++j) + for (size_t j : externals) { if (component->getNodeConnection(j) == neg1_) { @@ -234,9 +207,9 @@ namespace GridKit * * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable */ - int evaluateResidual() final + int evaluateInternalResidual() final { - for (IdxT i = 0; i < this->f_.size(); i++) + for (IdxT i = 0; i < this->getInternalSize(); i++) { f_[i] = 0.0; } @@ -244,14 +217,24 @@ namespace GridKit this->distributeVectors(); // Update system residual vector - for (const auto& component : components_) + + // Evaluate component internal residuals - this is embarassingly parallel + for (component_type* component : components_) + { + if (int err_code = component->evaluateInternalResidual()) + return err_code; + } + + for (component_type* component : components_) { - // TODO:check return type - component->evaluateResidual(); - IdxT size = component->size(); - const std::vector& residual = component->getResidual(); - for (IdxT j = 0; j < size; ++j) + if (int err_code = component->evaluateExternalResidual()) + return err_code; + + const std::vector& residual = component->getResidual(); + const std::set& externals = component->getExternIndices(); + + for (size_t j : externals) { //@todo should do a different grounding check if (component->getNodeConnection(j) != neg1_ && component->getNodeConnection(j) < this->getInternalSize()) @@ -264,6 +247,14 @@ namespace GridKit return 0; } + /** + * @todo implement this for nested systems + */ + int evaluateExternalResidual() final + { + return 0; + } + /** * @brief Creates the system Jacobian representing \alpha dF/dy' + dF/dy * @@ -349,7 +340,7 @@ namespace GridKit */ void printJacobianMatrixMarket(std::string filename, std::string title) { - jac_.printMatrixMarket(filename, title); + // jac_.printMatrixMarket(filename, title); } CsrMatrixT* getCsrJacobian() const override @@ -374,7 +365,7 @@ namespace GridKit int mapGlobalToLocal() { - for (const auto& component : components_) + for (auto* component : components_) { for (IdxT i = 0; i < component->size(); i++) @@ -396,6 +387,28 @@ namespace GridKit } } + for (auto* node : nodes_) + { + + for (IdxT i = 0; i < node->size(); i++) + { + IdxT index = node->getNodeConnection(i); + + if (index == neg1_) + { + continue; + } + else if (internal_map_.count(index) > 0) + { + node->setExternalConnectionNodes(i, internal_map_.at(index)); + } + else + { + node->setExternalConnectionNodes(i, external_map_.at(index)); + } + } + } + return 0; } @@ -404,6 +417,73 @@ namespace GridKit return 0; } + void createGlobalToInternalMap() + { + + std::vector global_indices; + + // First pass: Map global component indices to local subsystem indices. + for (component_type* comp : components_) + { + for (IdxT i = 0; i < comp->size(); i++) + { + IdxT index = comp->getNodeConnection(i); + + auto extern_indices = comp->getExternIndices(); + + if (index != neg1_ && !extern_indices.contains(i)) + { + global_indices.push_back(index); + } + } + } + + for (node_type* node : nodes_) + { + + for (IdxT i = 0; i < node->size(); i++) + { + IdxT index = node->getNodeConnection(i); + + if (index != neg1_) + { + global_indices.push_back(index); + } + } + } + + std::sort(global_indices.begin(), global_indices.end()); + + for (IdxT i = 0; i < global_indices.size(); i++) + { + internal_map_[global_indices[i]] = i; + } + + size_t counter = global_indices.size(); + for (component_type* comp : components_) + { + auto extern_indices = comp->getExternIndices(); + for (IdxT j = 0; j < comp->size(); j++) + { + if (!extern_indices.contains(j)) + { + continue; + } + IdxT index = comp->getNodeConnection(j); + + if (internal_map_.count(index) < 1 && external_map_.count(index) < 1 && index != neg1_) + { + external_map_[index] = counter++; + } + } + } + } + + std::vector& getExternalIndices() + { + return external_indices_; + } + std::vector& getExternalDataY() { return y_ext_; @@ -414,22 +494,32 @@ namespace GridKit return yp_ext_; } - std::vector& getExternalIndices() + void addNode(node_type* node) { - return external_indices_; + nodes_.push_back(node); + } + + void toString() + { + for (auto* comp : components_) + { + std::cout << ", " << std::to_string(comp->getIDcomponent()); + } + std::cout << std::endl; } private: static constexpr IdxT neg1_ = INVALID_INDEX; std::vector components_; + std::vector nodes_; std::unordered_map internal_map_; std::unordered_map external_map_; std::vector external_indices_; - std::vector y_ext_; - std::vector yp_ext_; - std::vector f_ext_; - IdxT refframe_index_{neg1_}; + bool root_; + std::vector y_ext_; + std::vector yp_ext_; + std::vector f_ext_; IdxT* map_to_csr_{nullptr}; CsrMatrixT* csr_jac_{nullptr}; From a1d5882976ffe0fb8b8d65790af233586f602de0 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Wed, 24 Jun 2026 22:09:58 +0000 Subject: [PATCH 14/34] Added partitioned scale microgrid example --- .../BusPartitionInterface.cpp | 89 +++-- .../BusPartitionInterface.hpp | 30 +- .../PartitionInterface/CMakeLists.txt | 2 - .../PartitionInterface/PartitionInterface.hpp | 38 --- .../Model/PowerElectronics/SubsystemModel.hpp | 31 +- .../PowerElectronics/Partition/CMakeLists.txt | 25 +- .../Partition/PartitionMicrogrid.cpp | 56 ++-- .../Partition/PartitionScaleMicrogrid.cpp | 311 +++++++++++++----- 8 files changed, 361 insertions(+), 221 deletions(-) diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp index 2e04e558d..0c4de184c 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp @@ -2,9 +2,9 @@ #include "BusPartitionInterface.hpp" #include +#include #include #include -#include namespace GridKit { @@ -26,21 +26,19 @@ namespace GridKit * @param id Unique component identifier. */ template - BusPartitionInterface::BusPartitionInterface(CircuitComponent& component, IdxT bus_i, IdxT bus_j, IdxT id) - : component_(component) + BusPartitionInterface::BusPartitionInterface(node_type& bus, component_type& component, IdxT id) + : component_(component), + bus_(bus) { - size_ = component.size(); + size_ = component_.size(); n_intern_ = 0; - n_extern_ = static_cast(component.size()); + n_extern_ = static_cast(component_.size()); idc_ = id; for (IdxT i = 0; i < size_; i++) { extern_indices_.insert(i); } - - bus_i_ = bus_i; - bus_j_ = bus_j; } template @@ -54,28 +52,51 @@ namespace GridKit template int BusPartitionInterface::allocate() { + + CircuitComponent::allocate(); + y_.resize(static_cast(size_)); yp_.resize(static_cast(size_)); f_.resize(static_cast(size_)); std::fill(f_.begin(), f_.end(), 0); + bool port_i_set = false; + bool port_j_set = false; - component_.allocate(); - - for (size_t i = 0; i < static_cast(component_.size()); i++) + for (size_t i = 0; i < static_cast(size_); i++) { - if (bus_i_ == component_.getNodeConnection(static_cast(i))) + if (bus_.getNodeConnection(0) == component_.getNodeConnection(static_cast(i))) { bus_port_i_ = i; + port_i_set = true; } - else if (bus_j_ == component_.getNodeConnection(static_cast(i))) + else if (bus_.getNodeConnection(1) == component_.getNodeConnection(static_cast(i))) { bus_port_j_ = i; + port_j_set = true; } IdxT global_idx = component_.getNodeConnection(static_cast(i)); this->setExternalConnectionNodes(static_cast(i), global_idx); } + if (!port_i_set || !port_j_set) + { + std::cerr << "ERROR: Invalid partition interface detected. " + << "Bus(ID=" << bus_.busID() + << "), Component(ID=" << component_.getIDcomponent() + << "). Please verify connection-node mappings and internal/external index assignments." + << std::endl; + assert(false); + } + + y_ptr = new ScalarT[component_.getInternalSize()]; + yp_ptr = new ScalarT[component_.getInternalSize()]; + f_ptr = new ScalarT[component_.getInternalSize()]; + + component_.setInternalPointer(y_ptr); + component_.setInternalDerivativePointer(yp_ptr); + component_.setInternalResidualPointer(f_ptr); + return 0; } @@ -101,18 +122,46 @@ namespace GridKit * @brief Eval Micro Load */ template - int BusPartitionInterface::evaluateResidual() + int BusPartitionInterface::evaluateInternalResidual() { - std::copy(y_.begin(), y_.end(), component_.y().begin()); - std::copy(yp_.begin(), yp_.end(), component_.yp().begin()); + return 0; + } - component_.evaluateResidual(); + /** + * @brief Eval Micro Load + */ + template + int BusPartitionInterface::evaluateExternalResidual() + { + + size_t counter_int = 0; + size_t counter_ext = 0; + auto extern_indices = component_.getExternIndices(); + + for (size_t i = 0; i < static_cast(component_.size()); i++) + { + if (extern_indices.contains(static_cast(i))) + { + component_.y()[counter_ext] = y_[i]; + component_.yp()[counter_ext] = yp_[i]; + counter_ext++; + } + else + { + y_ptr[counter_int] = y_[i]; + yp_ptr[counter_int] = yp_[i]; + counter_int++; + } + } - auto& f = component_.getResidual(); + component_.evaluateExternalResidual(); + auto f = component_.getResidual(); + + // TODO: This assumes that external variables are ordered after all internal + // variables in the local indexing. To make this more robust, we need to get rid of this assumption. f_[bus_port_i_] = f[bus_port_i_]; f_[bus_port_j_] = f[bus_port_j_]; - return 0; } @@ -126,8 +175,6 @@ namespace GridKit template int BusPartitionInterface::evaluateJacobian() { - jac_.zeroMatrix(); - return 0; } diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp index 1b1d9e4bd..2c08400b5 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp @@ -5,6 +5,7 @@ #include #include +#include #include "GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp" @@ -17,46 +18,45 @@ namespace GridKit template class BusPartitionInterface : public PartitionInterface { - using RealT = typename CircuitComponent::RealT; - using MatrixT = typename CircuitComponent::MatrixT; - using PartitionInterface::external_data_y_; - using PartitionInterface::external_data_yp_; - using PartitionInterface::interface_partition_externals_; - using PartitionInterface::bus_port_i_; - using PartitionInterface::bus_port_j_; - using PartitionInterface::bus_i_; - using PartitionInterface::bus_j_; + using component_type = CircuitComponent; + using node_type = typename PowerElectronics::NodeBase; using CircuitComponent::size_; 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::tag_; using CircuitComponent::f_; + using CircuitComponent::f_int_; using CircuitComponent::g_; using CircuitComponent::yB_; using CircuitComponent::ypB_; using CircuitComponent::fB_; using CircuitComponent::gB_; - using CircuitComponent::jac_; using CircuitComponent::param_; using CircuitComponent::idc_; + using PartitionInterface::bus_port_i_; + using PartitionInterface::bus_port_j_; + using CircuitComponent::extern_indices_; using CircuitComponent::n_extern_; using CircuitComponent::n_intern_; public: - BusPartitionInterface(CircuitComponent& component, IdxT bus_i, IdxT bus_j, IdxT id); + BusPartitionInterface(node_type& bus, component_type& component, IdxT id); virtual ~BusPartitionInterface(); int allocate(); int initialize(); int tagDifferentiable(); - int evaluateResidual(); + int evaluateInternalResidual() final; + int evaluateExternalResidual() final; int evaluateJacobian(); int evaluateIntegrand(); @@ -66,6 +66,10 @@ namespace GridKit int evaluateAdjointIntegrand(); private: - CircuitComponent& component_; + component_type& component_; + node_type& bus_; + ScalarT* y_ptr; + ScalarT* yp_ptr; + ScalarT* f_ptr; }; } // namespace GridKit diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/CMakeLists.txt b/GridKit/Model/PowerElectronics/PartitionInterface/CMakeLists.txt index 28fb804b0..938b2f6f1 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/CMakeLists.txt +++ b/GridKit/Model/PowerElectronics/PartitionInterface/CMakeLists.txt @@ -1,8 +1,6 @@ gridkit_add_library(power_elec_partition_interfaces SOURCES BusPartitionInterface.cpp - ComponentPartitionInterface.cpp HEADERS BusPartitionInterface.hpp - ComponentPartitionInterface.hpp PartitionInterface.hpp) diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp b/GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp index 85599404c..1e5a3c52d 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp @@ -2,9 +2,6 @@ #pragma once -#include -#include - #include #include #include @@ -36,44 +33,9 @@ namespace GridKit ~PartitionInterface() = default; - int setExternalDataY(const std::vector& data) - { - std::copy(data.begin(), data.end(), external_data_y_.begin()); - - return 0; - } - - int setExternalDataYP(const std::vector& data) - { - std::copy(data.begin(), data.end(), external_data_yp_.begin()); - - return 0; - } - - std::vector& getExternalDataY() - { - return external_data_y_; - } - - std::vector& getExternalDataYP() - { - return external_data_yp_; - } - - std::vector& getPartitionExternalIndices() - { - return interface_partition_externals_; - } - protected: - std::vector external_data_y_; - std::vector external_data_yp_; - std::vector interface_partition_externals_; - size_t bus_port_i_; size_t bus_port_j_; - IdxT bus_i_; - IdxT bus_j_; }; } // namespace GridKit diff --git a/GridKit/Model/PowerElectronics/SubsystemModel.hpp b/GridKit/Model/PowerElectronics/SubsystemModel.hpp index f2bfeb2dd..0ec483cfe 100644 --- a/GridKit/Model/PowerElectronics/SubsystemModel.hpp +++ b/GridKit/Model/PowerElectronics/SubsystemModel.hpp @@ -60,12 +60,6 @@ namespace GridKit virtual ~SubsystemModel() { - for (auto comp : this->components_) - { - delete comp; - } - delete csr_jac_; - delete[] map_to_csr_; } bool hasJacobian() final @@ -92,7 +86,7 @@ namespace GridKit n_intern_ = internal_map_.size(); n_extern_ = external_map_.size(); - size_ = n_intern_ + n_extern_; + size_ = n_intern_; CircuitComponent::allocate(); @@ -116,8 +110,6 @@ namespace GridKit for (const auto [global_idx, local_idx] : external_map_) { external_indices_[local_idx - n_intern_] = global_idx; - extern_indices_.insert(local_idx); - this->setExternalConnectionNodes(local_idx, global_idx); } { @@ -420,8 +412,7 @@ namespace GridKit void createGlobalToInternalMap() { - std::vector global_indices; - + size_t component_internal_idx = 0; // First pass: Map global component indices to local subsystem indices. for (component_type* comp : components_) { @@ -433,7 +424,7 @@ namespace GridKit if (index != neg1_ && !extern_indices.contains(i)) { - global_indices.push_back(index); + internal_map_[index] = component_internal_idx++; } } } @@ -447,19 +438,11 @@ namespace GridKit if (index != neg1_) { - global_indices.push_back(index); + internal_map_[index] = component_internal_idx++; } } } - std::sort(global_indices.begin(), global_indices.end()); - - for (IdxT i = 0; i < global_indices.size(); i++) - { - internal_map_[global_indices[i]] = i; - } - - size_t counter = global_indices.size(); for (component_type* comp : components_) { auto extern_indices = comp->getExternIndices(); @@ -473,7 +456,7 @@ namespace GridKit if (internal_map_.count(index) < 1 && external_map_.count(index) < 1 && index != neg1_) { - external_map_[index] = counter++; + external_map_[index] = component_internal_idx++; } } } @@ -484,12 +467,12 @@ namespace GridKit return external_indices_; } - std::vector& getExternalDataY() + std::vector& getExternalDataY() { return y_ext_; } - std::vector& getExternalDataYP() + std::vector& getExternalDataYP() { return yp_ext_; } diff --git a/examples/PowerElectronics/Partition/CMakeLists.txt b/examples/PowerElectronics/Partition/CMakeLists.txt index 2bc268e4f..00270b746 100644 --- a/examples/PowerElectronics/Partition/CMakeLists.txt +++ b/examples/PowerElectronics/Partition/CMakeLists.txt @@ -1,12 +1,25 @@ + +find_package(OpenMP REQUIRED) + add_executable(partition Partition.cpp) target_link_libraries(partition GridKit::solvers_dyn GridKit::power_elec_partition_interfaces) add_executable(partitionMicrogrid PartitionMicrogrid.cpp) -target_link_libraries(partitionMicrogrid GridKit::power_elec_disgen - GridKit::power_elec_microline - GridKit::power_elec_microload - GridKit::solvers_dyn - GridKit::power_elec_microbusdq - GridKit::power_elec_partition_interfaces) \ No newline at end of file +target_link_libraries(partitionMicrogrid GridKit::power_elec_disgen + GridKit::power_elec_microline + GridKit::power_elec_microload + GridKit::solvers_dyn + GridKit::power_elec_microbusdq + GridKit::power_elec_partition_interfaces) + + +add_executable(PartitionScaleMicrogrid PartitionScaleMicrogrid.cpp) +target_link_libraries(PartitionScaleMicrogrid GridKit::power_elec_disgen + GridKit::power_elec_microline + GridKit::power_elec_microload + GridKit::solvers_dyn + GridKit::power_elec_microbusdq + GridKit::power_elec_partition_interfaces + OpenMP::OpenMP_CXX) \ No newline at end of file diff --git a/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp b/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp index f9e00c37b..ff3d23a5d 100644 --- a/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp +++ b/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp @@ -1,6 +1,9 @@ #include #include #include +#include +#include +#include #define _USE_MATH_DEFINES #include @@ -26,6 +29,7 @@ int main() double rel_tol = 1.0e-8; size_t max_step_number = 3000; bool use_jac = true; + bool debug_output = true; // Create model auto* sysmodel = new GridKit::PowerElectronicsModel(rel_tol, abs_tol, use_jac, max_step_number); @@ -164,46 +168,35 @@ int main() sysmodel->allocate(); - GridKit::SubsystemModel* partition1 = new GridKit::SubsystemModel(false); - GridKit::SubsystemModel* partition2 = new GridKit::SubsystemModel(false); - GridKit::SubsystemModel* partition3 = new GridKit::SubsystemModel(false); - GridKit::SubsystemModel* partition4 = new GridKit::SubsystemModel(false); + GridKit::SubsystemModel* partition1 = new GridKit::SubsystemModel(); + GridKit::SubsystemModel* partition2 = new GridKit::SubsystemModel(); - GridKit::MicrogridLine l1copy(*l1); GridKit::MicrogridLine l2copy(*l2); - GridKit::MicrogridLine l3copy(*l3); - GridKit::BusPartitionInterface* busInterface1 = new GridKit::BusPartitionInterface(bus1, l1copy, 14); - GridKit::BusPartitionInterface* busInterface2 = new GridKit::BusPartitionInterface(bus2, l2copy, 15); - GridKit::BusPartitionInterface* busInterface3 = new GridKit::BusPartitionInterface(bus3, l3copy, 16); + GridKit::BusPartitionInterface* busInterface1 = new GridKit::BusPartitionInterface(bus2, l2copy, 14); busInterface1->allocate(); - busInterface2->allocate(); - busInterface3->allocate(); partition1->addNode(&dg_signal); partition1->addComponent(dg1); - partition1->addComponent(bus_para_1); - partition1->addNode(&bus1); + partition1->addComponent(dg2); + partition1->addComponent(l1); partition1->addComponent(load1); partition1->addComponent(busInterface1); + partition1->addComponent(bus_para_1); + partition1->addComponent(bus_para_2); + partition1->addNode(&bus1); + partition1->addNode(&bus2); - partition2->addComponent(dg2); - partition2->addComponent(l1); - partition2->addComponent(busInterface2); - partition2->addComponent(bus_para_2); - partition2->addNode(&bus2); - - partition3->addComponent(dg3); - partition3->addComponent(l2); - partition3->addComponent(busInterface3); - partition3->addComponent(load2); - partition3->addComponent(bus_para_3); - partition3->addNode(&bus3); + partition2->addComponent(dg3); + partition2->addComponent(dg4); + partition2->addComponent(l2); + partition2->addComponent(l3); - partition4->addComponent(dg4); - partition4->addComponent(l3); - partition4->addComponent(bus_para_4); - partition4->addNode(&bus4); + partition2->addComponent(load2); + partition2->addComponent(bus_para_4); + partition2->addComponent(bus_para_3); + partition2->addNode(&bus3); + partition2->addNode(&bus4); std::vector y; std::vector yp; @@ -225,10 +218,8 @@ int main() partition1->allocate(); partition2->allocate(); - partition3->allocate(); - partition4->allocate(); - std::vector*> partitions = {partition1, partition2, partition3, partition4}; + std::vector*> partitions = {partition1, partition2}; // Distribute externals to partition 1 for (auto* partition : partitions) @@ -293,6 +284,7 @@ int main() for (size_t i = 0; i < sysmodel->size(); i++) { error[i] = f_sysmodel[i] - f[i]; + std::cout << error[i] << std::endl; } double max_error = 0; diff --git a/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp b/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp index 178ad0a47..57f2448bd 100644 --- a/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp +++ b/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp @@ -1,6 +1,10 @@ +#include + +#include #include #include #include +#include #include #include #include @@ -20,6 +24,26 @@ #include #include +/****************************************************************************** + * Partitioned Residual Evaluation + * + * Construct subsystem models by partitioning the original microgrid into + * independent groups of components. Each subsystem is allocated and receives + * the appropriate subset of the global state vectors (y and yp), consisting + * of: + * + * - External variables (coupling variables from neighboring partitions) + * - Internal variables (states owned by the partition) + * + * After distributing the state information, each partition independently + * evaluates its residual. The local residuals are then scattered back into + * the global residual vector to reconstruct the monolithic residual. + * + * Finally, the reconstructed residual is compared against the reference + * monolithic evaluation to verify the correctness of the partitioning + * implementation. + ******************************************************************************/ + using index_type = size_t; using real_type = double; @@ -34,7 +58,7 @@ int printMicrogridSystems(index_type N_size); */ int main(int argc, char const* argv[]) { - // Default value + // Number of IBRs index_type N_size = 2; // Parse command line arguments if provided @@ -71,14 +95,15 @@ int printMicrogridSystems(index_type N_size) bool use_jac = true; - real_type rel_tol = 1e-5; - real_type abs_tol = 1e-5; + real_type rel_tol = 1e-5; + real_type abs_tol = 1e-5; + index_type max_steps = 2000; // Create circuit model - auto* sys_model = new PowerElectronicsModel(rel_tol, - abs_tol, - use_jac, - 2000); + auto* sys_model_control = new PowerElectronicsModel(rel_tol, + abs_tol, + use_jac, + max_steps); // Ensure minimum size requirement if (N_size < 1) @@ -164,26 +189,29 @@ int printMicrogridSystems(index_type N_size) Lload_list[0] = Lload1; } - using SignalNode = GridKit::PowerElectronics::SignalNode; - using Bus = GridKit::PowerElectronics::MicrogridBus; - using BusDQ = MicrogridBusDQ; - using Generator = DistributedGenerator; - using Line = MicrogridLine; - using Load = MicrogridLoad; - - std::vector buses(num_ibrs, nullptr); - std::vector busesDQ(num_ibrs, nullptr); - std::vector generators(num_ibrs, nullptr); - std::vector lines(num_ibrs, nullptr); - std::vector loads(num_ibrs, nullptr); + using SignalNode = GridKit::PowerElectronics::SignalNode; + using Bus = GridKit::PowerElectronics::MicrogridBus; + using BusDQ = MicrogridBusDQ; + using Generator = DistributedGenerator; + using Line = MicrogridLine; + using Load = MicrogridLoad; + using PartitionInterface = BusPartitionInterface; + + std::vector buses(num_ibrs, nullptr); + std::vector busesDQ(num_ibrs, nullptr); + std::vector generators(num_ibrs, nullptr); + std::vector lines(num_ibrs, nullptr); + std::vector loads(num_ibrs, nullptr); + std::vector partitionInterface; + std::vector linesCopies; SignalNode dg_signal; - sys_model->addNode(&dg_signal); + sys_model_control->addNode(&dg_signal); for (size_t i = 0; i < 2 * N_size; i++) { buses[i] = new Bus(); - sys_model->addNode(buses[i]); + sys_model_control->addNode(buses[i]); } // Create the reference DG @@ -192,7 +220,7 @@ int printMicrogridSystems(index_type N_size) true, &dg_signal, buses[0]); - sys_model->addComponent(dg_ref); + sys_model_control->addComponent(dg_ref); generators[0] = dg_ref; @@ -209,7 +237,7 @@ int printMicrogridSystems(index_type N_size) buses[i]); generators[i] = dg; - sys_model->addComponent(dg); + sys_model_control->addComponent(dg); } // Load all the Line components @@ -223,7 +251,7 @@ int printMicrogridSystems(index_type N_size) buses[i], buses[i + 1]); lines[i + 1] = line_model; - sys_model->addComponent(line_model); + sys_model_control->addComponent(line_model); } // Load all the Load components @@ -235,7 +263,7 @@ int printMicrogridSystems(index_type N_size) &dg_signal, buses[2 * i]); loads[2 * i] = load_model; - sys_model->addComponent(load_model); + sys_model_control->addComponent(load_model); } // Add all the microgrid Virtual DQ Buses @@ -244,84 +272,96 @@ int printMicrogridSystems(index_type N_size) auto* virDQbus_model = new MicrogridBusDQ(model_id++, RN, buses[i]); busesDQ[i] = virDQbus_model; - sys_model->addComponent(virDQbus_model); + sys_model_control->addComponent(virDQbus_model); } - sys_model->allocate(); + // sys_model_control->addNode(&dg_signal); + // for (index_type i = 0; i < num_ibrs; ++i) + // { + // sys_model_control->addComponent(generators[i]); + // sys_model_control->addComponent(busesDQ[i]); - std::vector y; - std::vector yp; + // if (loads[i] != nullptr) + // { + // sys_model_control->addComponent(loads[i]); + // } - for (size_t i = 0; i < sys_model->size(); i++) + // if (lines[i] != nullptr) + // { + // sys_model_control->addComponent(lines[i]); + // } + // sys_model_control->addNode(buses[i]); + // } + + sys_model_control->allocate(); + + std::vector y; + std::vector yp; + + for (size_t i = 0; i < sys_model_control->size(); i++) { - y.push_back(static_cast(i + 1)); - yp.push_back(static_cast(i + 1)); + y.push_back(static_cast(i + 1 + ((277 * i) % 100))); + yp.push_back(static_cast(i + 1 + ((288 * i) % 100))); } - for (size_t i = 0; i < sys_model->size(); i++) + auto start = std::chrono::high_resolution_clock::now(); + for (size_t i = 0; i < sys_model_control->size(); i++) { - sys_model->y()[i] = y[i]; - sys_model->yp()[i] = yp[i]; + sys_model_control->y()[i] = y[i]; + sys_model_control->yp()[i] = yp[i]; } - sys_model->evaluateResidual(); - std::vector f_sysmodel = sys_model->getResidual(); + sys_model_control->evaluateResidual(); + + auto end = std::chrono::high_resolution_clock::now(); + auto elapsed = std::chrono::duration(end - start); + std::cout << "Monolithic Evaluation Time: " << elapsed.count() << " s\n"; + + auto& f_sysmodel_control = sys_model_control->getResidual(); std::vector*> subsystems(num_partitions); - // Partition the system - index_type q = (num_ibrs) / num_partitions; - index_type r = (num_ibrs) % num_partitions; - index_type index = 0; - for (index_type j = 0; j < num_partitions; j++) - { - auto* partition = new SubsystemModel(false); + assert(num_ibrs % num_partitions == 0); + index_type partition_size = num_ibrs / num_partitions; + index_type index = 0; - // add Reference rotor to the first partition + for (index_type j = 0; j < num_partitions; ++j) + { + auto* partition = new SubsystemModel(); if (j == 0) { partition->addNode(&dg_signal); } - std::cout << "Partition " << j << std::endl; - - index_type part_size = q + (j < r ? 1 : 0); - index_type end = std::min(index + part_size, num_ibrs); - - // Add all components belonging to this partition - for (; index < end; ++index) + // Add components to belong to the same + for (index_type i = 0; i < partition_size; ++i) { partition->addComponent(generators[index]); - std::cout << "Comp Gen" << index << std::endl; partition->addComponent(busesDQ[index]); - std::cout << "Comp BDQ" << index << std::endl; if (loads[index] != nullptr) { partition->addComponent(loads[index]); - std::cout << "Comp Load" << index << std::endl; } if (lines[index] != nullptr) { partition->addComponent(lines[index]); - std::cout << "Comp Line" << index << std::endl; } - std::cout << "Comp Bus " << index << std::endl; - partition->addNode(buses[index]); + + index++; } - // Add partition interface at a partition point + // Add the partition interface to the left partition if (index < num_ibrs) { - auto* linecopy = new GridKit::MicrogridLine(*lines[index]); - - auto* busInterface = new GridKit::BusPartitionInterface(*buses[index - 1], *linecopy, model_id++); - busInterface->allocate(); + auto* linecopy = new GridKit::MicrogridLine(*lines[index]); + auto* busInterface = new GridKit::BusPartitionInterface(*buses[index - 1], *linecopy, model_id++); - std::cout << "Interface " << "(" << index - 1 << ", " << index << ")" << std::endl; + partitionInterface.push_back(busInterface); + linesCopies.push_back(linecopy); partition->addComponent(busInterface); } @@ -329,56 +369,67 @@ int printMicrogridSystems(index_type N_size) subsystems[j] = partition; } + std::vector f(sys_model_control->size(), 1.0); + std::vector error(sys_model_control->size(), 1.0); + + for (auto* partinterface : partitionInterface) + { + partinterface->allocate(); + } + for (auto* partition : subsystems) { - partition->toString(); partition->allocate(); } - // Distribute externals to partition 1 + start = std::chrono::high_resolution_clock::now(); + + auto sys_max_threads = omp_get_max_threads(); +// Distribute externals to partition 1 +#pragma omp parallel for schedule(guided) num_threads(sys_max_threads) for (auto* partition : subsystems) { + // Distribute external variables for (size_t i = 0; i < partition->getExternSize(); i++) { partition->getExternalDataY()[i] = y[partition->getExternalIndices()[i]]; partition->getExternalDataYP()[i] = yp[partition->getExternalIndices()[i]]; } - } - for (auto* partition : subsystems) - { + // Distribute internal variables for (size_t i = 0; i < partition->getInternalSize(); i++) { partition->y()[i] = y[partition->getNodeConnection(i)]; partition->yp()[i] = yp[partition->getNodeConnection(i)]; } - } - for (auto* partition : subsystems) - { + // Evaluate residual of this partition partition->evaluateResidual(); - } - - std::vector f(sys_model->size(), 0.0); - std::vector error(sys_model->size(), 1.0); - // Get internal residuals from partition 1 - for (auto* partition : subsystems) - { + // Reconstruct the monolithic residual from the partition residuals for (size_t i = 0; i < partition->getInternalSize(); i++) { f[partition->getNodeConnection(i)] = partition->getResidual()[i]; } } - for (size_t i = 0; i < sys_model->size(); i++) + end = std::chrono::high_resolution_clock::now(); + elapsed = std::chrono::duration(end - start); + std::cout << "Partition Evaluation Time: " << elapsed.count() << " s\n"; + + for (size_t i = 0; i < sys_model_control->size(); i++) { - error[i] = f_sysmodel[i] - f[i]; - std::cout << i << " " << error[i] << " ---------- " << i << std::endl; + error[i] = abs(f[i] - f_sysmodel_control[i]) / (f_sysmodel_control[i] + 1); + + std::cout << std::format("{:<8d} {:>15.15e} ---------- {:>15.15e} {:>15.5e}\n", + i, + error[i], + f[i], + f_sysmodel_control[i]); } - double max_error = 0; - for (size_t i = 0; i < sys_model->size(); i++) + real_type max_error = 0; + for (size_t i = 0; i < sys_model_control->size(); i++) { if (max_error < std::abs(error[i])) { @@ -386,7 +437,97 @@ int printMicrogridSystems(index_type N_size) } } - std::cout << "\nMax Error of Reference and Partition Evaluation: " << max_error << std::endl; + std::cout << "\nMax Rel. Error between Reference and Partition Evaluation: " << max_error + << std::endl + << std::endl; + + // real_type max_abs_error = 0.0; + // real_type max_rel_error = 0.0; + // size_t max_idx = 0; + + // for (size_t i = 0; i < sys_model_control->size(); ++i) + // { + // real_type abs_err = std::abs(f[i] - f_sysmodel_control[i]); + + // real_type scale = std::max({real_type(1.0), + // std::abs(f[i]), + // std::abs(f_sysmodel_control[i])}); + + // real_type rel_err = abs_err / scale; + + // if (rel_err > max_rel_error) + // { + // max_rel_error = rel_err; + // max_abs_error = abs_err; + // max_idx = i; + // } + // } + + // std::cout << "Max index : " << max_idx << '\n'; + // std::cout << "Partition f : " << std::format("{:.17e}", f[max_idx]) << '\n'; + // std::cout << "Monolithic f : " << std::format("{:.17e}", f_sysmodel_control[max_idx]) << '\n'; + // std::cout << "Abs error : " << std::format("{:.17e}", max_abs_error) << '\n'; + // std::cout << "Rel error : " << std::format("{:.17e}", max_rel_error) << '\n'; + + for (auto* linescpy : linesCopies) + { + delete linescpy; + } + + for (auto* partition : subsystems) + { + delete partition; + } + delete sys_model_control; return 0; } + +// Partition the system +// index_type q = (num_ibrs) / num_partitions; +// index_type r = (num_ibrs) % num_partitions; +// index_type index = 0; +// for (index_type j = 0; j < num_partitions; j++) +// { +// auto* partition = new SubsystemModel(false); + +// // add Reference rotor to the first partition +// if (j == 0) +// { +// partition->addNode(&dg_signal); +// } + +// index_type part_size = q + (j < r ? 1 : 0); +// index_type end = std::min(index + part_size, num_ibrs); + +// // Add all components belonging to this partition +// for (; index < end; ++index) +// { +// partition->addComponent(generators[index]); +// partition->addComponent(busesDQ[index]); + +// if (loads[index] != nullptr) +// { +// partition->addComponent(loads[index]); +// } + +// if (lines[index] != nullptr) +// { +// partition->addComponent(lines[index]); +// } + +// partition->addNode(buses[index]); +// } + +// // Add partition interface at a partition point +// if (index < num_ibrs) +// { +// auto* linecopy = new GridKit::MicrogridLine(*lines[index]); + +// auto* busInterface = new GridKit::BusPartitionInterface(*buses[index - 1], *linecopy, model_id++); +// busInterface->allocate(); +// partition->addComponent(busInterface); +// } + +// subsystems[j] = partition; +// } From 91ac7681379d927c46ef086b56d0063afa98336d Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Fri, 26 Jun 2026 23:55:17 +0000 Subject: [PATCH 15/34] Rmoved obsolete interfaces and clean up partitioning code --- .../ComponentPartitionInterface.cpp | 174 -------------- .../ComponentPartitionInterface.hpp | 74 ------ .../Model/PowerElectronics/SubsystemModel.hpp | 2 - .../Partition/PartitionScaleMicrogrid.cpp | 223 +++++++++--------- 4 files changed, 111 insertions(+), 362 deletions(-) delete mode 100644 GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.cpp delete mode 100644 GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.hpp diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.cpp b/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.cpp deleted file mode 100644 index c5a06ae66..000000000 --- a/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.cpp +++ /dev/null @@ -1,174 +0,0 @@ - - -#include "ComponentPartitionInterface.hpp" - -#include -#include -#include -#include - -namespace GridKit -{ - - /*! - * @brief Constructor for the ComponentPartitionInterface - * - * - * - * - */ - - template - ComponentPartitionInterface::ComponentPartitionInterface(CircuitComponent* component, IdxT bus_i, IdxT bus_j, IdxT id) - : component_(component) - { - size_ = component_->size(); - n_intern_ = component_->getInternalSize(); - n_extern_ = component_->getExternSize(); - extern_indices_ = component_->getExternIndices(); - idc_ = id; - - bus_i_ = bus_i; - bus_j_ = bus_j; - } - - template - ComponentPartitionInterface::~ComponentPartitionInterface() - { - } - - /*! - * @brief allocate method. - */ - template - int ComponentPartitionInterface::allocate() - { - - size_t bus_size = 2; - - y_.resize(static_cast(size_)); - yp_.resize(static_cast(size_)); - f_.resize(static_cast(size_)); - interface_partition_externals_.resize(bus_size); - external_data_y_.resize(bus_size, 0); - external_data_yp_.resize(bus_size, 0); - - component_->allocate(); - - for (size_t i = 0; i < static_cast(size_); i++) - { - auto index = component_->getNodeConnection(static_cast(i)); - if (bus_i_ == index) - { - bus_port_i_ = i; - } - else if (bus_j_ == index) - { - bus_port_j_ = i; - } - else - { - this->setExternalConnectionNodes(static_cast(i), index); - } - } - - this->setExternalConnectionNodes(static_cast(bus_port_i_), static_cast(-1)); - this->setExternalConnectionNodes(static_cast(bus_port_j_), static_cast(-1)); - - interface_partition_externals_[0] = bus_i_; - interface_partition_externals_[1] = bus_j_; - - return 0; - } - - /** - * Initialization - */ - template - int ComponentPartitionInterface::initialize() - { - return 0; - } - - /* - * - */ - template - int ComponentPartitionInterface::tagDifferentiable() - { - return 0; - } - - /** - * @brief - */ - template - int ComponentPartitionInterface::evaluateResidual() - { - - auto& y = component_->y(); - auto& yp = component_->yp(); - - std::copy(y_.begin(), y_.end(), y.begin()); - std::copy(yp_.begin(), yp_.end(), yp.begin()); - - y[bus_port_i_] = external_data_y_[0]; - y[bus_port_j_] = external_data_y_[1]; - - yp[bus_port_i_] = external_data_yp_[0]; - yp[bus_port_j_] = external_data_yp_[1]; - - component_->evaluateResidual(); - auto& f = component_->getResidual(); - - std::copy(f.begin(), f.end(), f_.begin()); - - return 0; - } - - /** - * @brief Generate Jacobian for Micro Load - * - * @tparam ScalarT - * @tparam IdxT - * @return int - */ - template - int ComponentPartitionInterface::evaluateJacobian() - { - jac_.zeroMatrix(); - - return 0; - } - - template - int ComponentPartitionInterface::evaluateIntegrand() - { - return 0; - } - - template - int ComponentPartitionInterface::initializeAdjoint() - { - return 0; - } - - template - int ComponentPartitionInterface::evaluateAdjointResidual() - { - return 0; - } - - template - int ComponentPartitionInterface::evaluateAdjointIntegrand() - { - return 0; - } - - // Available template instantiations - template class ComponentPartitionInterface; - template class ComponentPartitionInterface; - template class ComponentPartitionInterface; - template class ComponentPartitionInterface; - -} // namespace GridKit diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.hpp b/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.hpp deleted file mode 100644 index a46231f6d..000000000 --- a/GridKit/Model/PowerElectronics/PartitionInterface/ComponentPartitionInterface.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include - -#include - -#include "GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp" - -namespace GridKit -{ - template - class BaseBus; -} - -namespace GridKit -{ - /*! - * @brief Declaration of a passive ComponentPartitionInterface class. - * - */ - template - class ComponentPartitionInterface : public PartitionInterface - { - using RealT = typename CircuitComponent::RealT; - using MatrixT = typename CircuitComponent::MatrixT; - - using PartitionInterface::external_data_y_; - using PartitionInterface::external_data_yp_; - using PartitionInterface::interface_partition_externals_; - using PartitionInterface::bus_port_i_; - using PartitionInterface::bus_port_j_; - using PartitionInterface::bus_i_; - using PartitionInterface::bus_j_; - - using CircuitComponent::size_; - using CircuitComponent::nnz_; - using CircuitComponent::time_; - using CircuitComponent::alpha_; - using CircuitComponent::y_; - using CircuitComponent::yp_; - using CircuitComponent::tag_; - using CircuitComponent::f_; - using CircuitComponent::g_; - using CircuitComponent::yB_; - using CircuitComponent::ypB_; - using CircuitComponent::fB_; - using CircuitComponent::gB_; - using CircuitComponent::jac_; - using CircuitComponent::param_; - using CircuitComponent::idc_; - using CircuitComponent::extern_indices_; - using CircuitComponent::n_extern_; - using CircuitComponent::n_intern_; - - public: - ComponentPartitionInterface(CircuitComponent* component, IdxT bus_i, IdxT bus_j, IdxT id); - virtual ~ComponentPartitionInterface(); - - int allocate(); - int initialize(); - int tagDifferentiable(); - int evaluateResidual(); - int evaluateJacobian(); - int evaluateIntegrand(); - - int initializeAdjoint(); - int evaluateAdjointResidual(); - // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); - - private: - CircuitComponent* component_; - }; -} // namespace GridKit diff --git a/GridKit/Model/PowerElectronics/SubsystemModel.hpp b/GridKit/Model/PowerElectronics/SubsystemModel.hpp index 0ec483cfe..c8aceb2cf 100644 --- a/GridKit/Model/PowerElectronics/SubsystemModel.hpp +++ b/GridKit/Model/PowerElectronics/SubsystemModel.hpp @@ -235,7 +235,6 @@ namespace GridKit } } } - return 0; } @@ -332,7 +331,6 @@ namespace GridKit */ void printJacobianMatrixMarket(std::string filename, std::string title) { - // jac_.printMatrixMarket(filename, title); } CsrMatrixT* getCsrJacobian() const override diff --git a/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp b/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp index 57f2448bd..f0c0cdf8d 100644 --- a/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp +++ b/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -47,7 +48,16 @@ using index_type = size_t; using real_type = double; -int printMicrogridSystems(index_type N_size); +struct RunResult +{ + index_type num_partitions; + real_type partition_time; // seconds + real_type monolithic_time; // seconds + real_type speedup; // monolithic / partition + real_type max_error; +}; + +RunResult printMicrogridSystems(index_type N_size, index_type num_partitions); /** * @brief Run Scale Microgrid for a specific N given by the user. @@ -58,24 +68,33 @@ int printMicrogridSystems(index_type N_size); */ int main(int argc, char const* argv[]) { - // Number of IBRs - index_type N_size = 2; + index_type N_size = 5000; + + std::cout << std::format("{:<16}{:>16}{:>18}{:>12}{:>14}\n", + "num_partitions", + "partition_time", + "monolithic_time", + "speedup", + "error"); + + std::cout << std::string(76, '-') << "\n"; - // Parse command line arguments if provided - if (argc > 1) + for (index_type p : {10, 100, 1000, 2000}) { - try - { - N_size = static_cast(std::stoi(argv[1])); - } - catch (const std::exception& e) - { - std::cerr << "Error parsing grid size argument: " << e.what() << std::endl; - std::cerr << "Using default grid size = " << N_size << std::endl; - } + if ((2 * N_size) % p != 0) // assert(num_ibrs % num_partitions == 0) + continue; + + RunResult r = printMicrogridSystems(N_size, p); + + std::cout << std::format("{:<16d}{:>14.3f} s{:>16.3f} s{:>11.2f}x{:>14.3e}\n", + r.num_partitions, + r.partition_time, + r.monolithic_time, + r.speedup, + r.max_error); } - return printMicrogridSystems(N_size); + return 0; } /** @@ -84,12 +103,11 @@ int main(int argc, char const* argv[]) * @param[in] N_size - The number of DG line load cobinations to generate for scale * @return int returns 0 if successful, >0 otherwise */ -int printMicrogridSystems(index_type N_size) +RunResult printMicrogridSystems(index_type N_size, index_type num_partitions) { using namespace GridKit; - const size_t num_ibrs = 2 * N_size; - const size_t num_partitions = 4; + const index_type num_ibrs = 2 * N_size; assert(num_partitions <= num_ibrs); @@ -106,11 +124,7 @@ int printMicrogridSystems(index_type N_size) max_steps); // Ensure minimum size requirement - if (N_size < 1) - { - std::cout << "N_size must be at least 1.\n"; - return 1; - } + assert(N_size >= 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. @@ -206,12 +220,12 @@ int printMicrogridSystems(index_type N_size) std::vector linesCopies; SignalNode dg_signal; - sys_model_control->addNode(&dg_signal); + // sys_model_control->addNode(&dg_signal); for (size_t i = 0; i < 2 * N_size; i++) { buses[i] = new Bus(); - sys_model_control->addNode(buses[i]); + // sys_model_control->addNode(buses[i]); } // Create the reference DG @@ -220,7 +234,7 @@ int printMicrogridSystems(index_type N_size) true, &dg_signal, buses[0]); - sys_model_control->addComponent(dg_ref); + // sys_model_control->addComponent(dg_ref); generators[0] = dg_ref; @@ -237,7 +251,7 @@ int printMicrogridSystems(index_type N_size) buses[i]); generators[i] = dg; - sys_model_control->addComponent(dg); + // sys_model_control->addComponent(dg); } // Load all the Line components @@ -251,7 +265,7 @@ int printMicrogridSystems(index_type N_size) buses[i], buses[i + 1]); lines[i + 1] = line_model; - sys_model_control->addComponent(line_model); + // sys_model_control->addComponent(line_model); } // Load all the Load components @@ -263,7 +277,7 @@ int printMicrogridSystems(index_type N_size) &dg_signal, buses[2 * i]); loads[2 * i] = load_model; - sys_model_control->addComponent(load_model); + // sys_model_control->addComponent(load_model); } // Add all the microgrid Virtual DQ Buses @@ -272,26 +286,26 @@ int printMicrogridSystems(index_type N_size) auto* virDQbus_model = new MicrogridBusDQ(model_id++, RN, buses[i]); busesDQ[i] = virDQbus_model; - sys_model_control->addComponent(virDQbus_model); + // sys_model_control->addComponent(virDQbus_model); } - // sys_model_control->addNode(&dg_signal); - // for (index_type i = 0; i < num_ibrs; ++i) - // { - // sys_model_control->addComponent(generators[i]); - // sys_model_control->addComponent(busesDQ[i]); - - // if (loads[i] != nullptr) - // { - // sys_model_control->addComponent(loads[i]); - // } - - // if (lines[i] != nullptr) - // { - // sys_model_control->addComponent(lines[i]); - // } - // sys_model_control->addNode(buses[i]); - // } + sys_model_control->addNode(&dg_signal); + for (index_type i = 0; i < num_ibrs; ++i) + { + sys_model_control->addComponent(generators[i]); + sys_model_control->addComponent(busesDQ[i]); + + if (loads[i] != nullptr) + { + sys_model_control->addComponent(loads[i]); + } + + if (lines[i] != nullptr) + { + sys_model_control->addComponent(lines[i]); + } + sys_model_control->addNode(buses[i]); + } sys_model_control->allocate(); @@ -300,11 +314,12 @@ int printMicrogridSystems(index_type N_size) for (size_t i = 0; i < sys_model_control->size(); i++) { - y.push_back(static_cast(i + 1 + ((277 * i) % 100))); - yp.push_back(static_cast(i + 1 + ((288 * i) % 100))); + y.push_back(static_cast(i + 1)); + yp.push_back(static_cast(i + 1)); } - auto start = std::chrono::high_resolution_clock::now(); + auto start_time = std::chrono::high_resolution_clock::now(); + for (size_t i = 0; i < sys_model_control->size(); i++) { sys_model_control->y()[i] = y[i]; @@ -313,12 +328,20 @@ int printMicrogridSystems(index_type N_size) sys_model_control->evaluateResidual(); - auto end = std::chrono::high_resolution_clock::now(); - auto elapsed = std::chrono::duration(end - start); - std::cout << "Monolithic Evaluation Time: " << elapsed.count() << " s\n"; + auto end_time = std::chrono::high_resolution_clock::now(); + auto monolithic_time = std::chrono::duration(end_time - start_time); auto& f_sysmodel_control = sys_model_control->getResidual(); + //--------------------------------------------------------------- + // Partition the monolithic network into independent subsystem + // models. Each subsystem owns a contiguous block of generators, + // buses, lines, and loads. Whenever a partition boundary is + // encountered, a BusPartitionInterface is inserted to expose the + // neighboring partition's boundary variables while maintaining + // the same electrical connectivity as the original network. + //--------------------------------------------------------------- + std::vector*> subsystems(num_partitions); assert(num_ibrs % num_partitions == 0); @@ -360,6 +383,7 @@ int printMicrogridSystems(index_type N_size) auto* linecopy = new GridKit::MicrogridLine(*lines[index]); auto* busInterface = new GridKit::BusPartitionInterface(*buses[index - 1], *linecopy, model_id++); + busInterface->allocate(); partitionInterface.push_back(busInterface); linesCopies.push_back(linecopy); @@ -369,20 +393,25 @@ int printMicrogridSystems(index_type N_size) subsystems[j] = partition; } + //--------------------------------------------------------------- + // Allocate each subsystem and evaluate the partitioned residual. + // + // The global state vectors (y and yp) are scattered into the + // corresponding internal and external vectors of every subsystem. + // After evaluating the residuals independently, the local + // residuals are gathered back into the global residual vector for + // comparison with the monolithic evaluation. + //--------------------------------------------------------------- + std::vector f(sys_model_control->size(), 1.0); std::vector error(sys_model_control->size(), 1.0); - for (auto* partinterface : partitionInterface) - { - partinterface->allocate(); - } - for (auto* partition : subsystems) { partition->allocate(); } - start = std::chrono::high_resolution_clock::now(); + start_time = std::chrono::high_resolution_clock::now(); auto sys_max_threads = omp_get_max_threads(); // Distribute externals to partition 1 @@ -406,81 +435,51 @@ int printMicrogridSystems(index_type N_size) // Evaluate residual of this partition partition->evaluateResidual(); - // Reconstruct the monolithic residual from the partition residuals + // Reconstructs the monolithic residual from the partition residuals for (size_t i = 0; i < partition->getInternalSize(); i++) { f[partition->getNodeConnection(i)] = partition->getResidual()[i]; } } - end = std::chrono::high_resolution_clock::now(); - elapsed = std::chrono::duration(end - start); - std::cout << "Partition Evaluation Time: " << elapsed.count() << " s\n"; + end_time = std::chrono::high_resolution_clock::now(); + auto partition_time = std::chrono::duration(end_time - start_time); - for (size_t i = 0; i < sys_model_control->size(); i++) - { - error[i] = abs(f[i] - f_sysmodel_control[i]) / (f_sysmodel_control[i] + 1); - - std::cout << std::format("{:<8d} {:>15.15e} ---------- {:>15.15e} {:>15.5e}\n", - i, - error[i], - f[i], - f_sysmodel_control[i]); - } + //--------------------------------------------------------------- + // Compare the reconstructed partition residual against the + // reference monolithic residual. The per-entry error is computed + // and the maximum error is reported to verify that the partitioned + // formulation reproduces the monolithic model within numerical + // roundoff. + //--------------------------------------------------------------- real_type max_error = 0; for (size_t i = 0; i < sys_model_control->size(); i++) { - if (max_error < std::abs(error[i])) + error[i] = abs(f[i] - f_sysmodel_control[i]) / (f_sysmodel_control[i] + 1); + + if (max_error < error[i]) { - max_error = std::abs(error[i]); + max_error = error[i]; } } - std::cout << "\nMax Rel. Error between Reference and Partition Evaluation: " << max_error - << std::endl - << std::endl; - - // real_type max_abs_error = 0.0; - // real_type max_rel_error = 0.0; - // size_t max_idx = 0; - - // for (size_t i = 0; i < sys_model_control->size(); ++i) - // { - // real_type abs_err = std::abs(f[i] - f_sysmodel_control[i]); - - // real_type scale = std::max({real_type(1.0), - // std::abs(f[i]), - // std::abs(f_sysmodel_control[i])}); - - // real_type rel_err = abs_err / scale; - - // if (rel_err > max_rel_error) - // { - // max_rel_error = rel_err; - // max_abs_error = abs_err; - // max_idx = i; - // } - // } - - // std::cout << "Max index : " << max_idx << '\n'; - // std::cout << "Partition f : " << std::format("{:.17e}", f[max_idx]) << '\n'; - // std::cout << "Monolithic f : " << std::format("{:.17e}", f_sysmodel_control[max_idx]) << '\n'; - // std::cout << "Abs error : " << std::format("{:.17e}", max_abs_error) << '\n'; - // std::cout << "Rel error : " << std::format("{:.17e}", max_rel_error) << '\n'; + RunResult result; + result.num_partitions = num_partitions; + result.partition_time = partition_time.count(); + result.monolithic_time = monolithic_time.count(); + result.speedup = monolithic_time.count() / partition_time.count(); + result.max_error = max_error; for (auto* linescpy : linesCopies) - { delete linescpy; - } - for (auto* partition : subsystems) - { delete partition; - } + for (auto* part_interface : partitionInterface) + delete part_interface; delete sys_model_control; - return 0; + return result; } // Partition the system From 1b940185aa527206413b21997d7a41d1784d9afe Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Sat, 27 Jun 2026 00:28:53 +0000 Subject: [PATCH 16/34] Partition Scale Microgrid configured with 10000IBRs --- .../Partition/PartitionScaleMicrogrid.cpp | 90 ++++--------------- 1 file changed, 19 insertions(+), 71 deletions(-) diff --git a/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp b/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp index f0c0cdf8d..c55447fad 100644 --- a/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp +++ b/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp @@ -4,10 +4,7 @@ #include #include #include -#include #include -#include -#include #include #include #include @@ -66,7 +63,7 @@ RunResult printMicrogridSystems(index_type N_size, index_type num_partitions); * @param[in] argv can contain the N value (argv[1]) * @return int */ -int main(int argc, char const* argv[]) +int main() { index_type N_size = 5000; @@ -79,14 +76,13 @@ int main(int argc, char const* argv[]) std::cout << std::string(76, '-') << "\n"; - for (index_type p : {10, 100, 1000, 2000}) + for (index_type p : {10, 48, 100, 500, 1000, 2000, 5000}) { - if ((2 * N_size) % p != 0) // assert(num_ibrs % num_partitions == 0) - continue; + assert(p <= 2 * N_size); RunResult r = printMicrogridSystems(N_size, p); - std::cout << std::format("{:<16d}{:>14.3f} s{:>16.3f} s{:>11.2f}x{:>14.3e}\n", + std::cout << std::format("{:<16d}{:>14.4f} s{:>16.4f} s{:>11.2f}x{:>14.3e}\n", r.num_partitions, r.partition_time, r.monolithic_time, @@ -344,20 +340,25 @@ RunResult printMicrogridSystems(index_type N_size, index_type num_partitions) std::vector*> subsystems(num_partitions); - assert(num_ibrs % num_partitions == 0); - index_type partition_size = num_ibrs / num_partitions; - index_type index = 0; - - for (index_type j = 0; j < num_partitions; ++j) + // Partition the system + index_type q = (num_ibrs) / num_partitions; + index_type r = (num_ibrs) % num_partitions; + index_type index = 0; + for (index_type j = 0; j < num_partitions; j++) { - auto* partition = new SubsystemModel(); + auto* partition = new SubsystemModel(false); + + // add Reference rotor to the first partition if (j == 0) { partition->addNode(&dg_signal); } - // Add components to belong to the same - for (index_type i = 0; i < partition_size; ++i) + index_type part_size = q + (j < r ? 1 : 0); + index_type end = std::min(index + part_size, num_ibrs); + + // Add all components belonging to this partition + for (; index < end; ++index) { partition->addComponent(generators[index]); partition->addComponent(busesDQ[index]); @@ -373,10 +374,7 @@ RunResult printMicrogridSystems(index_type N_size, index_type num_partitions) } partition->addNode(buses[index]); - - index++; } - // Add the partition interface to the left partition if (index < num_ibrs) { @@ -413,9 +411,8 @@ RunResult printMicrogridSystems(index_type N_size, index_type num_partitions) start_time = std::chrono::high_resolution_clock::now(); - auto sys_max_threads = omp_get_max_threads(); // Distribute externals to partition 1 -#pragma omp parallel for schedule(guided) num_threads(sys_max_threads) +#pragma omp parallel for schedule(guided) for (auto* partition : subsystems) { // Distribute external variables @@ -480,53 +477,4 @@ RunResult printMicrogridSystems(index_type N_size, index_type num_partitions) delete sys_model_control; return result; -} - -// Partition the system -// index_type q = (num_ibrs) / num_partitions; -// index_type r = (num_ibrs) % num_partitions; -// index_type index = 0; -// for (index_type j = 0; j < num_partitions; j++) -// { -// auto* partition = new SubsystemModel(false); - -// // add Reference rotor to the first partition -// if (j == 0) -// { -// partition->addNode(&dg_signal); -// } - -// index_type part_size = q + (j < r ? 1 : 0); -// index_type end = std::min(index + part_size, num_ibrs); - -// // Add all components belonging to this partition -// for (; index < end; ++index) -// { -// partition->addComponent(generators[index]); -// partition->addComponent(busesDQ[index]); - -// if (loads[index] != nullptr) -// { -// partition->addComponent(loads[index]); -// } - -// if (lines[index] != nullptr) -// { -// partition->addComponent(lines[index]); -// } - -// partition->addNode(buses[index]); -// } - -// // Add partition interface at a partition point -// if (index < num_ibrs) -// { -// auto* linecopy = new GridKit::MicrogridLine(*lines[index]); - -// auto* busInterface = new GridKit::BusPartitionInterface(*buses[index - 1], *linecopy, model_id++); -// busInterface->allocate(); -// partition->addComponent(busInterface); -// } - -// subsystems[j] = partition; -// } +} \ No newline at end of file From 08f320af35ea1ffa76b73e67664ca6246b773c71 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Mon, 6 Jul 2026 19:49:41 -0400 Subject: [PATCH 17/34] Added Jacobian contributions for bus interfaces --- .../BusPartitionInterface.cpp | 89 ++++++++++++++----- .../BusPartitionInterface.hpp | 9 +- .../PowerElectronics/Partition/CMakeLists.txt | 8 +- 3 files changed, 79 insertions(+), 27 deletions(-) diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp index 0c4de184c..ebab170a8 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp @@ -39,6 +39,28 @@ namespace GridKit { extern_indices_.insert(i); } + + + const IdxT* cooRow = component_->jacobianCooRows(); + const IdxT* cooCol = component_->jacobianCooCols(); + + const IdxT bus_i = bus.getNodeConnection(0); + const IdxT bus_j = bus.getNodeConnection(1); + + for (IdxT k = 0; k < component_->nnz(); ++k) + { + const IdxT row_node = component.getNodeConnection(cooRow[k]); + const IdxT col_node = component.getNodeConnection(cooCol[k]); + + const bool row_is_bus = (row_node == bus_i || row_node == bus_j); + const bool col_is_bus = (col_node == bus_i || col_node == bus_j); + + if (row_is_bus && col_is_bus) + { + ++nnz_; + jac_map_.push_back(i); + } + } } template @@ -89,13 +111,16 @@ namespace GridKit assert(false); } - y_ptr = new ScalarT[component_.getInternalSize()]; - yp_ptr = new ScalarT[component_.getInternalSize()]; - f_ptr = new ScalarT[component_.getInternalSize()]; + + const auto n = component_.getInternalSize(); - component_.setInternalPointer(y_ptr); - component_.setInternalDerivativePointer(yp_ptr); - component_.setInternalResidualPointer(f_ptr); + y_ptr = std::make_unique(n); + yp_ptr = std::make_unique(n); + f_ptr = std::make_unique(n); + + component_.setInternalPointer(y_ptr.get()); + component_.setInternalDerivativePointer(yp_ptr.get()); + component_.setInternalResidualPointer(f_ptr.get()); return 0; } @@ -134,24 +159,26 @@ namespace GridKit int BusPartitionInterface::evaluateExternalResidual() { - size_t counter_int = 0; - size_t counter_ext = 0; - auto extern_indices = component_.getExternIndices(); + size_t internal = 0; + size_t external = 0; + + const auto& extern_indices = component_.getExternIndices(); - for (size_t i = 0; i < static_cast(component_.size()); i++) + for (IdxT i = 0; i < component_.size(); ++i) { - if (extern_indices.contains(static_cast(i))) - { - component_.y()[counter_ext] = y_[i]; - component_.yp()[counter_ext] = yp_[i]; - counter_ext++; - } - else + const bool is_external = extern_indices.contains(i); + + if (is_external) { - y_ptr[counter_int] = y_[i]; - yp_ptr[counter_int] = yp_[i]; - counter_int++; + component_.y()[external] = y_[i]; + component_.yp()[external] = yp_[i]; + ++external; + continue; } + + y_ptr[internal] = y_[i]; + yp_ptr[internal] = yp_[i]; + ++internal; } component_.evaluateExternalResidual(); @@ -175,6 +202,28 @@ namespace GridKit template int BusPartitionInterface::evaluateJacobian() { + this->zeroJacMatrix(); + + component_->evaluateJacobian(); + + const IdxT* cooRow = component_->jacobianCooRows(); + const IdxT* cooCol = component_->jacobianCooCols(); + const RealT* cooVals = component_->jacobianCooValues(); + + std::vector r = {}; + std::vector c = {}; + std::vector v = {}; + + + for(const auto& index: jac_map_) + { + r.push_back(cooRow[index]); + c.push_back(cooCol[index]); + v.push_back(cooVals[index]); + } + + this->setJacValues(r, c, v); + return 0; } diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp index 2c08400b5..3f9bc1a64 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp @@ -68,8 +68,11 @@ namespace GridKit private: component_type& component_; node_type& bus_; - ScalarT* y_ptr; - ScalarT* yp_ptr; - ScalarT* f_ptr; + + std::unique_ptr y_ptr; + std::unique_ptr yp_ptr; + std::unique_ptr f_ptr; + + std::vector jac_map_; }; } // namespace GridKit diff --git a/examples/PowerElectronics/Partition/CMakeLists.txt b/examples/PowerElectronics/Partition/CMakeLists.txt index 00270b746..6876c4754 100644 --- a/examples/PowerElectronics/Partition/CMakeLists.txt +++ b/examples/PowerElectronics/Partition/CMakeLists.txt @@ -1,9 +1,9 @@ find_package(OpenMP REQUIRED) -add_executable(partition Partition.cpp) -target_link_libraries(partition GridKit::solvers_dyn - GridKit::power_elec_partition_interfaces) +#add_executable(partition Partition.cpp) +#target_link_libraries(partition GridKit::solvers_dyn +# GridKit::power_elec_partition_interfaces) add_executable(partitionMicrogrid PartitionMicrogrid.cpp) @@ -22,4 +22,4 @@ target_link_libraries(PartitionScaleMicrogrid GridKit::power_elec_disgen GridKit::solvers_dyn GridKit::power_elec_microbusdq GridKit::power_elec_partition_interfaces - OpenMP::OpenMP_CXX) \ No newline at end of file + OpenMP::OpenMP_CXX) From b4a62ff2aaf9af9ca9920e8bba3e5473b6abebb5 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Sat, 27 Jun 2026 04:23:37 +0000 Subject: [PATCH 18/34] Benchmark Setup for Parallel Function Evaluation --- .../Partition/PartitionScaleMicrogrid.cpp | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp b/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp index c55447fad..6d1a37666 100644 --- a/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp +++ b/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp @@ -4,10 +4,11 @@ #include #include #include +<<<<<<< HEAD #include + ======= +>>>>>>> 5723ffb9 (Benchmark Setup for Parallel Function Evaluation) #include -#include -#include #include #include @@ -22,28 +23,28 @@ #include #include -/****************************************************************************** - * Partitioned Residual Evaluation - * - * Construct subsystem models by partitioning the original microgrid into - * independent groups of components. Each subsystem is allocated and receives - * the appropriate subset of the global state vectors (y and yp), consisting - * of: - * - * - External variables (coupling variables from neighboring partitions) - * - Internal variables (states owned by the partition) - * - * After distributing the state information, each partition independently - * evaluates its residual. The local residuals are then scattered back into - * the global residual vector to reconstruct the monolithic residual. - * - * Finally, the reconstructed residual is compared against the reference - * monolithic evaluation to verify the correctness of the partitioning - * implementation. - ******************************************************************************/ - -using index_type = size_t; -using real_type = double; + /****************************************************************************** + * Partitioned Residual Evaluation + * + * Construct subsystem models by partitioning the original microgrid into + * independent groups of components. Each subsystem is allocated and receives + * the appropriate subset of the global state vectors (y and yp), consisting + * of: + * + * - External variables (coupling variables from neighboring partitions) + * - Internal variables (states owned by the partition) + * + * After distributing the state information, each partition independently + * evaluates its residual. The local residuals are then scattered back into + * the global residual vector to reconstruct the monolithic residual. + * + * Finally, the reconstructed residual is compared against the reference + * monolithic evaluation to verify the correctness of the partitioning + * implementation. + ******************************************************************************/ + + using index_type = size_t; +using real_type = double; struct RunResult { From 3937b52214fb6b593bd899f1e6e3d64a314c21b5 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Tue, 7 Jul 2026 02:31:38 +0000 Subject: [PATCH 19/34] Minor updates --- .../BusPartitionInterface.cpp | 24 +++++----- .../BusPartitionInterface.hpp | 1 + .../Partition/PartitionScaleMicrogrid.cpp | 48 +++++++++---------- 3 files changed, 35 insertions(+), 38 deletions(-) diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp index ebab170a8..0ede5de02 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp @@ -41,16 +41,16 @@ namespace GridKit } - const IdxT* cooRow = component_->jacobianCooRows(); - const IdxT* cooCol = component_->jacobianCooCols(); + const IdxT* cooRow = component_.jacobianCooRows(); + const IdxT* cooCol = component_.jacobianCooCols(); const IdxT bus_i = bus.getNodeConnection(0); const IdxT bus_j = bus.getNodeConnection(1); - for (IdxT k = 0; k < component_->nnz(); ++k) + for (IdxT k = 0; k < component_.nnz(); ++k) { - const IdxT row_node = component.getNodeConnection(cooRow[k]); - const IdxT col_node = component.getNodeConnection(cooCol[k]); + const IdxT row_node = component_.getNodeConnection(cooRow[k]); + const IdxT col_node = component_.getNodeConnection(cooCol[k]); const bool row_is_bus = (row_node == bus_i || row_node == bus_j); const bool col_is_bus = (col_node == bus_i || col_node == bus_j); @@ -58,7 +58,7 @@ namespace GridKit if (row_is_bus && col_is_bus) { ++nnz_; - jac_map_.push_back(i); + jac_map_.push_back(k); } } } @@ -204,11 +204,11 @@ namespace GridKit { this->zeroJacMatrix(); - component_->evaluateJacobian(); + component_.evaluateJacobian(); - const IdxT* cooRow = component_->jacobianCooRows(); - const IdxT* cooCol = component_->jacobianCooCols(); - const RealT* cooVals = component_->jacobianCooValues(); + const IdxT* cooRows = component_.jacobianCooRows(); + const IdxT* cooCols = component_.jacobianCooCols(); + const RealT* cooVals = component_.jacobianCooValues(); std::vector r = {}; std::vector c = {}; @@ -217,8 +217,8 @@ namespace GridKit for(const auto& index: jac_map_) { - r.push_back(cooRow[index]); - c.push_back(cooCol[index]); + r.push_back(cooRows[index]); + c.push_back(cooCols[index]); v.push_back(cooVals[index]); } diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp index 3f9bc1a64..1bda78a89 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp @@ -21,6 +21,7 @@ namespace GridKit using component_type = CircuitComponent; using node_type = typename PowerElectronics::NodeBase; + using RealT = typename CircuitComponent::RealT; using CircuitComponent::size_; using CircuitComponent::nnz_; diff --git a/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp b/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp index 6d1a37666..4e59848c8 100644 --- a/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp +++ b/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp @@ -4,10 +4,6 @@ #include #include #include -<<<<<<< HEAD -#include - ======= ->>>>>>> 5723ffb9 (Benchmark Setup for Parallel Function Evaluation) #include #include @@ -23,28 +19,28 @@ #include #include - /****************************************************************************** - * Partitioned Residual Evaluation - * - * Construct subsystem models by partitioning the original microgrid into - * independent groups of components. Each subsystem is allocated and receives - * the appropriate subset of the global state vectors (y and yp), consisting - * of: - * - * - External variables (coupling variables from neighboring partitions) - * - Internal variables (states owned by the partition) - * - * After distributing the state information, each partition independently - * evaluates its residual. The local residuals are then scattered back into - * the global residual vector to reconstruct the monolithic residual. - * - * Finally, the reconstructed residual is compared against the reference - * monolithic evaluation to verify the correctness of the partitioning - * implementation. - ******************************************************************************/ - - using index_type = size_t; -using real_type = double; +/****************************************************************************** + * Partitioned Residual Evaluation + * + * Construct subsystem models by partitioning the original microgrid into + * independent groups of components. Each subsystem is allocated and receives + * the appropriate subset of the global state vectors (y and yp), consisting + * of: + * + * - External variables (coupling variables from neighboring partitions) + * - Internal variables (states owned by the partition) + * + * After distributing the state information, each partition independently + * evaluates its residual. The local residuals are then scattered back into + * the global residual vector to reconstruct the monolithic residual. + * + * Finally, the reconstructed residual is compared against the reference + * monolithic evaluation to verify the correctness of the partitioning + * implementation. + ******************************************************************************/ + +using index_type = size_t; +using real_type = double; struct RunResult { From 8762af80e07cc006336f86b1b0938c393a2e8673 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Mon, 6 Jul 2026 23:16:43 -0400 Subject: [PATCH 20/34] Added subsystem Jacobian --- .../Model/PowerElectronics/SubsystemModel.hpp | 166 ++++++++++++++---- 1 file changed, 133 insertions(+), 33 deletions(-) diff --git a/GridKit/Model/PowerElectronics/SubsystemModel.hpp b/GridKit/Model/PowerElectronics/SubsystemModel.hpp index c8aceb2cf..ea6ee31fb 100644 --- a/GridKit/Model/PowerElectronics/SubsystemModel.hpp +++ b/GridKit/Model/PowerElectronics/SubsystemModel.hpp @@ -112,7 +112,7 @@ namespace GridKit external_indices_[local_idx - n_intern_] = global_idx; } - { + size_t component_internal_idx = 0; for (component_type* comp : components_) { @@ -121,16 +121,96 @@ namespace GridKit comp->setInternalDerivativePointer(&yp_[component_internal_idx]); comp->setInternalResidualPointer(&f_[component_internal_idx]); - const auto& external_indices = comp->getExternIndices(); - for (size_t i = 0; i < comp->size(); i++) - { - if (!external_indices.contains(i)) - { - component_internal_idx++; - } - } + component_internal_idx += comp->getInternalSize(); } - } + + + // // Evaluate component Jacobians to get sparsity + // distributeVectors(); + // for (component_type* component : components_) + // { + // component->evaluateJacobian(); + // } + + // // Count the number of non-zeros + // IdxT nnz_dup = 0; + // for (const component_type* component : components_) + // { + // const IdxT* r = component->jacobianCooRows(); + // const IdxT* c = component->jacobianCooCols(); + // IdxT nnz = component->nnz(); + + // for (IdxT i = 0; i < nnz; ++i) + // { + // if(component->getNodeConnection(r[i])>= this->getInternalSize() && component->getNodeConnection(c[i])>= this->getInternalSize()) + // { + // continue; + // } + // if (component->getNodeConnection(r[i]) != neg1_ && component->getNodeConnection(c[i]) != neg1_) + // { + // ++nnz_dup; + // } + // } + // } + + // // Allocate COO triplet arrays (we own these until we hand off to CsrMatrix) + // IdxT* rows_dup = new IdxT[nnz_dup]; + // IdxT* cols_dup = new IdxT[nnz_dup]; + // RealT* vals_dup = new RealT[nnz_dup]; + + // IdxT counter = 0; + // for (const auto& component : components_) + // { + // const IdxT* r = component->jacobianCooRows(); + // const IdxT* c = component->jacobianCooCols(); + // const RealT* v = component->jacobianCooValues(); + // IdxT nnz = component->nnz(); + + // for (IdxT i = 0; i < nnz; ++i) + // { + // if(component->getNodeConnection(r[i])>= this->getInternalSize() && component->getNodeConnection(c[i])>= this->getInternalSize()) + // { + // continue; + // } + + // if (component->getNodeConnection(r[i]) != neg1_ && component->getNodeConnection(c[i]) != neg1_) + // { + // rows_dup[counter] = component->getNodeConnection(r[i]); + // cols_dup[counter] = component->getNodeConnection(c[i]); + // vals_dup[counter] = v[i]; + // counter++; + // } + // } + // } + + // // Build the system COO Jacobian + // LinearAlgebra::CooMatrix jac(size_, size_, nnz_dup, &rows_dup, &cols_dup, &vals_dup); + + // // Populate CSR data with sort and deduplicate + // IdxT* row_ptrs = jac.getCsrRowData(); + + // // Deduplicated nnz + // nnz_ = jac.getNnz(); + + // // Allocate cols/vals with deduplicated nnz + // IdxT* cols = new IdxT[nnz_]; + // RealT* vals = new RealT[nnz_]; + + // std::copy(jac.getColData(), jac.getColData() + nnz_, cols); + // std::copy(jac.getValues(), jac.getValues() + nnz_, vals); + + // // Create the CSR Jacobian + // csr_jac_ = new CsrMatrixT(size_, size_, nnz_, &row_ptrs, &cols, &vals); + + // const IdxT* map_to_sorted = jac.getMapToSorted(); + // const IdxT* map_to_dedup = jac.getMapToDeduplicated(); + + // // Build a mappping from original COO index to CSR index + // map_to_csr_ = new IdxT[nnz_dup]; + // for (IdxT i = 0; i < nnz_dup; ++i) + // { + // map_to_csr_[map_to_sorted[i]] = map_to_dedup[i]; + // } return 0; } @@ -254,6 +334,45 @@ namespace GridKit */ int evaluateJacobian() final { + + distributeVectors(); + + // Zero out values + RealT* vals = csr_jac_->getValues(); + for (IdxT i = 0; i < csr_jac_->getNnz(); ++i) + { + vals[i] = 0.0; + } + + // Update CSR values from component Jacobians + IdxT counter = 0; + for (const auto& component : components_) + { + component->evaluateJacobian(); + + const IdxT* r = component->jacobianCooRows(); + const IdxT* c = component->jacobianCooCols(); + const RealT* v = component->jacobianCooValues(); + IdxT nnz = component->nnz(); + + for (IdxT i = 0; i < nnz; ++i) + { + + if(component->getNodeConnection(r[i]) >= this->getInternalSize() && component->getNodeConnection(c[i]) >= this->getInternalSize()) + { + continue; + } + + if (component->getNodeConnection(r[i]) != neg1_ && component->getNodeConnection(c[i]) != neg1_) + { + vals[map_to_csr_[counter]] += v[i]; + ++counter; + } + } + } + + jac_call_count_++; + return 0; } @@ -343,14 +462,9 @@ namespace GridKit components_.push_back(component); } - std::unordered_map& getInternalMap() - { - return internal_map_; - } - - std::unordered_map& getExternalMap() + void addNode(node_type* node) { - return external_map_; + nodes_.push_back(node); } int mapGlobalToLocal() @@ -402,11 +516,6 @@ namespace GridKit return 0; } - int mapLocalToGlobal() - { - return 0; - } - void createGlobalToInternalMap() { @@ -475,18 +584,9 @@ namespace GridKit return yp_ext_; } - void addNode(node_type* node) - { - nodes_.push_back(node); - } - - void toString() + std::vector& getExternalDataF() { - for (auto* comp : components_) - { - std::cout << ", " << std::to_string(comp->getIDcomponent()); - } - std::cout << std::endl; + return f_ext_; } private: From 28671aad0b178d4a939bbdda104d7d9faa3fbb08 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Mon, 13 Jul 2026 17:20:30 +0000 Subject: [PATCH 21/34] Updated Hires test problem --- .../PowerElectronics/Partition/CMakeLists.txt | 6 +- .../PowerElectronics/Partition/HiresBus.hpp | 33 ++++++---- .../Partition/HiresComponent1.hpp | 47 +++++++++++---- .../Partition/HiresComponent3.hpp | 60 +++++++++++++++---- 4 files changed, 109 insertions(+), 37 deletions(-) diff --git a/examples/PowerElectronics/Partition/CMakeLists.txt b/examples/PowerElectronics/Partition/CMakeLists.txt index 6876c4754..cdb522167 100644 --- a/examples/PowerElectronics/Partition/CMakeLists.txt +++ b/examples/PowerElectronics/Partition/CMakeLists.txt @@ -1,9 +1,9 @@ find_package(OpenMP REQUIRED) -#add_executable(partition Partition.cpp) -#target_link_libraries(partition GridKit::solvers_dyn -# GridKit::power_elec_partition_interfaces) +add_executable(partition Partition.cpp) +target_link_libraries(partition GridKit::solvers_dyn + GridKit::power_elec_partition_interfaces) add_executable(partitionMicrogrid PartitionMicrogrid.cpp) diff --git a/examples/PowerElectronics/Partition/HiresBus.hpp b/examples/PowerElectronics/Partition/HiresBus.hpp index 585d25ce0..eeb7f6080 100644 --- a/examples/PowerElectronics/Partition/HiresBus.hpp +++ b/examples/PowerElectronics/Partition/HiresBus.hpp @@ -19,15 +19,17 @@ namespace GridKit using CircuitComponent::time_; using CircuitComponent::alpha_; using CircuitComponent::y_; + using CircuitComponent::y_int_; using CircuitComponent::yp_; + using CircuitComponent::yp_int_; using CircuitComponent::tag_; using CircuitComponent::f_; + using CircuitComponent::f_int_; using CircuitComponent::g_; using CircuitComponent::yB_; using CircuitComponent::ypB_; using CircuitComponent::fB_; using CircuitComponent::gB_; - using CircuitComponent::jac_; using CircuitComponent::param_; using CircuitComponent::idc_; @@ -39,10 +41,11 @@ namespace GridKit HiresBus(IdxT id) { size_ = 2; - n_intern_ = 2; - n_extern_ = 0; - extern_indices_ = {}; + n_intern_ = 0; + n_extern_ = 2; + extern_indices_ = {0, 1}; idc_ = id; + nnz_ = 2; } ~HiresBus() @@ -51,9 +54,7 @@ namespace GridKit int allocate() { - y_.resize(static_cast(size_)); - yp_.resize(static_cast(size_)); - f_.resize(static_cast(size_)); + CircuitComponent::allocate(); return 0; } @@ -68,16 +69,28 @@ namespace GridKit return 0; } - int evaluateResidual() + int evaluateInternalResidual() { - f_[0] = yp_[0] + y_[0]; - f_[1] = yp_[1] + y_[1]; + return 0; + } + int evaluateExternalResidual() + { + f_[0] = -yp_[0] - y_[0]; + f_[1] = -yp_[1] - y_[1]; return 0; } int evaluateJacobian() { + this->zeroJacMatrix(); + + std::vector row = {0, 1}; + std::vector col = {0, 1}; + std::vector val = {-alpha_ - 1.0, -alpha_ - 1.0}; + + this->setJacValues(row, col, val); + return 0; } diff --git a/examples/PowerElectronics/Partition/HiresComponent1.hpp b/examples/PowerElectronics/Partition/HiresComponent1.hpp index 1d6c51fc8..d72a7a068 100644 --- a/examples/PowerElectronics/Partition/HiresComponent1.hpp +++ b/examples/PowerElectronics/Partition/HiresComponent1.hpp @@ -21,15 +21,17 @@ namespace GridKit using CircuitComponent::time_; using CircuitComponent::alpha_; using CircuitComponent::y_; + using CircuitComponent::y_int_; using CircuitComponent::yp_; + using CircuitComponent::yp_int_; using CircuitComponent::tag_; using CircuitComponent::f_; + using CircuitComponent::f_int_; using CircuitComponent::g_; using CircuitComponent::yB_; using CircuitComponent::ypB_; using CircuitComponent::fB_; using CircuitComponent::gB_; - using CircuitComponent::jac_; using CircuitComponent::param_; using CircuitComponent::idc_; @@ -45,6 +47,7 @@ namespace GridKit n_extern_ = 2; extern_indices_ = {0, 1}; idc_ = id; + nnz_ = 12; } ~HiresComponent1() @@ -53,9 +56,7 @@ namespace GridKit int allocate() { - y_.resize(static_cast(size_)); - yp_.resize(static_cast(size_)); - f_.resize(static_cast(size_)); + CircuitComponent::allocate(); return 0; } @@ -70,23 +71,45 @@ namespace GridKit return 0; } - int evaluateResidual() + int evaluateInternalResidual() { - // outputs - f_[0] = -8.32 * y_[3] - 1.71 * y_[4] + 0.1 * y_[0]; - f_[1] = +0.7 * y_[1]; - // Internals - f_[2] = yp_[2] + 1.71 * y_[2] - 0.43 * y_[3] - 8.32 * y_[4] - 0.0007; - f_[3] = yp_[3] - 1.71 * y_[2] + 8.75 * y_[3]; - f_[4] = yp_[4] + 10.03 * y_[4] - 0.43 * y_[0] - 0.035 * y_[1]; + f_int_[0] = -yp_int_[0] - 1.71 * y_int_[0] + 0.43 * y_int_[1] + 8.32 * y_int_[2] + 0.0007; + f_int_[1] = -yp_int_[1] + 1.71 * y_int_[0] - 8.75 * y_int_[1]; + f_int_[2] = -yp_int_[2] - 10.03 * y_int_[2] + 0.43 * y_[0] + 0.035 * y_[1]; + + return 0; + } + + int evaluateExternalResidual() + { + // outputs + f_[0] = 8.32 * y_int_[1] + 1.71 * y_int_[2] - 0.1 * y_[0]; + f_[1] = -0.7 * y_[1]; return 0; } int evaluateJacobian() { + + this->zeroJacMatrix(); + + // Internal Jacobian Entries + std::vector row = {2, 2, 2, 3, 3, 4, 4, 4}; + std::vector col = {2, 3, 4, 2, 3, 4, 0, 1}; + std::vector val = {-1.71 - alpha_, 0.43, 8.32, 1.71, -8.75 - alpha_, -10.03 - alpha_, 0.43, 0.035}; + + this->setJacValues(row, col, val); + + // External Jacobian Entries + row = {0, 0, 0, 1}; + col = {3, 4, 0, 1}; + val = {8.32, 1.71, -0.1, -0.7}; + + this->setJacValues(row, col, val); + return 0; } diff --git a/examples/PowerElectronics/Partition/HiresComponent3.hpp b/examples/PowerElectronics/Partition/HiresComponent3.hpp index d0b71f5c1..81314895d 100644 --- a/examples/PowerElectronics/Partition/HiresComponent3.hpp +++ b/examples/PowerElectronics/Partition/HiresComponent3.hpp @@ -21,15 +21,17 @@ namespace GridKit using CircuitComponent::time_; using CircuitComponent::alpha_; using CircuitComponent::y_; + using CircuitComponent::y_int_; using CircuitComponent::yp_; + using CircuitComponent::yp_int_; using CircuitComponent::tag_; using CircuitComponent::f_; + using CircuitComponent::f_int_; using CircuitComponent::g_; using CircuitComponent::yB_; using CircuitComponent::ypB_; using CircuitComponent::fB_; using CircuitComponent::gB_; - using CircuitComponent::jac_; using CircuitComponent::param_; using CircuitComponent::idc_; @@ -45,6 +47,7 @@ namespace GridKit n_extern_ = 2; extern_indices_ = {0, 1}; idc_ = id; + nnz_ = 15; } ~HiresComponent3() @@ -53,9 +56,7 @@ namespace GridKit int allocate() { - y_.resize(static_cast(size_)); - yp_.resize(static_cast(size_)); - f_.resize(static_cast(size_)); + CircuitComponent::allocate(); return 0; } @@ -70,22 +71,57 @@ namespace GridKit return 0; } - int evaluateResidual() + int evaluateInternalResidual() { - // Outputs - f_[0] = 0.02 * y_[0]; - f_[1] = 0.045 * y_[1] - 0.43 * y_[2] - 0.43 * y_[3]; - // Internals - f_[2] = yp_[2] + 280 * y_[2] * y_[4] - 0.69 * y_[0] - 1.71 * y_[1] + 0.43 * y_[2] - 0.69 * y_[3]; - f_[3] = yp_[3] - 280 * y_[2] * y_[4] + 1.81 * y_[3]; - f_[4] = yp_[4] + 280 * y_[2] * y_[4] - 1.81 * y_[3]; + f_int_[0] = -yp_int_[0] - 280 * y_int_[0] * y_int_[2] + 0.69 * y_[0] + 1.71 * y_[1] - 0.43 * y_int_[0] + 0.69 * y_int_[1]; + f_int_[1] = -yp_int_[1] + 280 * y_int_[0] * y_int_[2] - 1.81 * y_int_[1]; + f_int_[2] = -yp_int_[2] - 280 * y_int_[0] * y_int_[2] + 1.81 * y_int_[1]; + + return 0; + } + + int evaluateExternalResidual() + { + // Externals + f_[0] = -0.02 * y_[0]; + f_[1] = -0.045 * y_[1] + 0.43 * y_int_[0] + 0.43 * y_int_[1]; return 0; } int evaluateJacobian() { + this->zeroJacMatrix(); + + // Internal Jacobian Entries [row 1] + std::vector row = {2, 2, 2, 2, 2}; + std::vector col = {2, 3, 4, 0, 1}; + std::vector val = {-280 * y_int_[2] - 0.43 - alpha_, 0.69, -280 * y_int_[0], 0.69, 1.71}; + + this->setJacValues(row, col, val); + + // Internal Jacobian Entries [row 2] + row = {3, 3, 3}; + col = {2, 3, 4}; + val = {280 * y_int_[2], -1.81 - alpha_, 280 * y_int_[0]}; + + this->setJacValues(row, col, val); + + // Internal Jacobian Entries [row 3] + row = {4, 4, 4}; + col = {2, 3, 4}; + val = {-280 * y_int_[2], 1.81, -280 * y_int_[0] - alpha_}; + + this->setJacValues(row, col, val); + + // External Jacobian Entries + row = {0, 1, 1, 1}; + col = {0, 2, 3, 1}; + val = {-0.02, 0.43, 0.43, -0.045}; + + this->setJacValues(row, col, val); + return 0; } From 48b0285825b79cf520b7602b38d43c256b934bc4 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Mon, 13 Jul 2026 17:21:19 +0000 Subject: [PATCH 22/34] Add subsystem Jacobian testing utilities and update partition test problems --- GridKit/Model/PartitionEvaluator.hpp | 2 +- GridKit/Model/PowerElectronics/CMakeLists.txt | 1 - .../BusPartitionInterface.cpp | 15 +- .../PartitionInterface/CMakeLists.txt | 10 +- .../Model/PowerElectronics/SubsystemModel.hpp | 339 +++++++++++------- .../Solver/Dynamic/MultiStageCosimulation.cpp | 2 +- .../PowerElectronics/Partition/CMakeLists.txt | 37 +- .../PowerElectronics/Partition/HiresBus.hpp | 2 +- .../PowerElectronics/Partition/Partition.cpp | 153 +++++++- .../Partition/PartitionMicrogrid.cpp | 72 ++-- .../Partition/PartitionScaleMicrogrid.cpp | 67 +++- .../Partition/jac_test_helper.hpp | 250 +++++++++++++ 12 files changed, 717 insertions(+), 233 deletions(-) create mode 100644 examples/PowerElectronics/Partition/jac_test_helper.hpp diff --git a/GridKit/Model/PartitionEvaluator.hpp b/GridKit/Model/PartitionEvaluator.hpp index 96d906ea3..1ce80b513 100644 --- a/GridKit/Model/PartitionEvaluator.hpp +++ b/GridKit/Model/PartitionEvaluator.hpp @@ -279,4 +279,4 @@ namespace GridKit }; } // namespace Model -} // namespace GridKit \ No newline at end of file +} // namespace GridKit diff --git a/GridKit/Model/PowerElectronics/CMakeLists.txt b/GridKit/Model/PowerElectronics/CMakeLists.txt index 199df1684..efe1c7f68 100644 --- a/GridKit/Model/PowerElectronics/CMakeLists.txt +++ b/GridKit/Model/PowerElectronics/CMakeLists.txt @@ -31,4 +31,3 @@ install( NodeBase.hpp SubsystemModel.hpp DESTINATION include/GridKit/Model/PowerElectronics) - diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp index 0ede5de02..85d8d43fb 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp @@ -40,7 +40,6 @@ namespace GridKit extern_indices_.insert(i); } - const IdxT* cooRow = component_.jacobianCooRows(); const IdxT* cooCol = component_.jacobianCooCols(); @@ -111,7 +110,6 @@ namespace GridKit assert(false); } - const auto n = component_.getInternalSize(); y_ptr = std::make_unique(n); @@ -206,16 +204,15 @@ namespace GridKit component_.evaluateJacobian(); - const IdxT* cooRows = component_.jacobianCooRows(); - const IdxT* cooCols = component_.jacobianCooCols(); - const RealT* cooVals = component_.jacobianCooValues(); + const IdxT* cooRows = component_.jacobianCooRows(); + const IdxT* cooCols = component_.jacobianCooCols(); + const RealT* cooVals = component_.jacobianCooValues(); - std::vector r = {}; - std::vector c = {}; + std::vector r = {}; + std::vector c = {}; std::vector v = {}; - - for(const auto& index: jac_map_) + for (const auto& index : jac_map_) { r.push_back(cooRows[index]); c.push_back(cooCols[index]); diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/CMakeLists.txt b/GridKit/Model/PowerElectronics/PartitionInterface/CMakeLists.txt index 938b2f6f1..b339bfa2f 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/CMakeLists.txt +++ b/GridKit/Model/PowerElectronics/PartitionInterface/CMakeLists.txt @@ -1,6 +1,4 @@ -gridkit_add_library(power_elec_partition_interfaces - SOURCES - BusPartitionInterface.cpp - HEADERS - BusPartitionInterface.hpp - PartitionInterface.hpp) +gridkit_add_library( + power_elec_partition_interfaces + SOURCES BusPartitionInterface.cpp + HEADERS BusPartitionInterface.hpp PartitionInterface.hpp) diff --git a/GridKit/Model/PowerElectronics/SubsystemModel.hpp b/GridKit/Model/PowerElectronics/SubsystemModel.hpp index ea6ee31fb..1fdb79193 100644 --- a/GridKit/Model/PowerElectronics/SubsystemModel.hpp +++ b/GridKit/Model/PowerElectronics/SubsystemModel.hpp @@ -3,6 +3,8 @@ #pragma once #include +#include +#include #include #include #include @@ -15,6 +17,7 @@ namespace GridKit { + template class SubsystemModel : public CircuitComponent { @@ -23,6 +26,8 @@ namespace GridKit using CsrMatrixT = typename CircuitComponent::CsrMatrixT; using component_type = CircuitComponent; using node_type = PowerElectronics::NodeBase; + using ForcingData = std::pair, std::vector>; + using TimeFunction = std::function; using CircuitComponent::size_; using CircuitComponent::n_intern_; @@ -47,7 +52,7 @@ namespace GridKit * @post System model parameters set as default */ - SubsystemModel(bool root = true) + SubsystemModel() { // Set system model parameters as default rel_tol_ = 1e-4; @@ -55,7 +60,6 @@ namespace GridKit this->max_steps_ = 2000; // By default don't use the jacobian use_jac_ = false; - root_ = root; } virtual ~SubsystemModel() @@ -93,6 +97,7 @@ namespace GridKit y_.resize(n_intern_); yp_.resize(n_intern_); f_.resize(n_intern_); + neumaier_compensation.resize(n_intern_); // Allocate subsystem vectors. y_ext_.resize(n_extern_); @@ -112,105 +117,117 @@ namespace GridKit external_indices_[local_idx - n_intern_] = global_idx; } - - size_t component_internal_idx = 0; - for (component_type* comp : components_) + size_t component_internal_idx = 0; + for (component_type* comp : components_) + { + + comp->setInternalPointer(&y_[component_internal_idx]); + comp->setInternalDerivativePointer(&yp_[component_internal_idx]); + comp->setInternalResidualPointer(&f_[component_internal_idx]); + + component_internal_idx += comp->getInternalSize(); + } + + // Evaluate component Jacobians to get sparsity + distributeVectors(); + for (component_type* component : components_) + { + component->evaluateJacobian(); + } + + auto isValidEntry = [this](IdxT row, IdxT col) + { + if (row == neg1_ || col == neg1_) { + return false; + } + + const bool row_is_internal = row < this->getInternalSize(); + const bool col_is_internal = col < this->getInternalSize(); - comp->setInternalPointer(&y_[component_internal_idx]); - comp->setInternalDerivativePointer(&yp_[component_internal_idx]); - comp->setInternalResidualPointer(&f_[component_internal_idx]); + return (row_is_internal && col_is_internal); + }; + + IdxT nnz_dup = 0; + + for (const component_type* component : components_) + { + const IdxT* r = component->jacobianCooRows(); + const IdxT* c = component->jacobianCooCols(); + const IdxT nnz = component->nnz(); - component_internal_idx += comp->getInternalSize(); + for (IdxT i = 0; i < nnz; ++i) + { + const IdxT row = component->getNodeConnection(r[i]); + const IdxT col = component->getNodeConnection(c[i]); + + if (isValidEntry(row, col)) + { + ++nnz_dup; + } } - - - // // Evaluate component Jacobians to get sparsity - // distributeVectors(); - // for (component_type* component : components_) - // { - // component->evaluateJacobian(); - // } - - // // Count the number of non-zeros - // IdxT nnz_dup = 0; - // for (const component_type* component : components_) - // { - // const IdxT* r = component->jacobianCooRows(); - // const IdxT* c = component->jacobianCooCols(); - // IdxT nnz = component->nnz(); - - // for (IdxT i = 0; i < nnz; ++i) - // { - // if(component->getNodeConnection(r[i])>= this->getInternalSize() && component->getNodeConnection(c[i])>= this->getInternalSize()) - // { - // continue; - // } - // if (component->getNodeConnection(r[i]) != neg1_ && component->getNodeConnection(c[i]) != neg1_) - // { - // ++nnz_dup; - // } - // } - // } - - // // Allocate COO triplet arrays (we own these until we hand off to CsrMatrix) - // IdxT* rows_dup = new IdxT[nnz_dup]; - // IdxT* cols_dup = new IdxT[nnz_dup]; - // RealT* vals_dup = new RealT[nnz_dup]; - - // IdxT counter = 0; - // for (const auto& component : components_) - // { - // const IdxT* r = component->jacobianCooRows(); - // const IdxT* c = component->jacobianCooCols(); - // const RealT* v = component->jacobianCooValues(); - // IdxT nnz = component->nnz(); - - // for (IdxT i = 0; i < nnz; ++i) - // { - // if(component->getNodeConnection(r[i])>= this->getInternalSize() && component->getNodeConnection(c[i])>= this->getInternalSize()) - // { - // continue; - // } - - // if (component->getNodeConnection(r[i]) != neg1_ && component->getNodeConnection(c[i]) != neg1_) - // { - // rows_dup[counter] = component->getNodeConnection(r[i]); - // cols_dup[counter] = component->getNodeConnection(c[i]); - // vals_dup[counter] = v[i]; - // counter++; - // } - // } - // } - - // // Build the system COO Jacobian - // LinearAlgebra::CooMatrix jac(size_, size_, nnz_dup, &rows_dup, &cols_dup, &vals_dup); - - // // Populate CSR data with sort and deduplicate - // IdxT* row_ptrs = jac.getCsrRowData(); - - // // Deduplicated nnz - // nnz_ = jac.getNnz(); - - // // Allocate cols/vals with deduplicated nnz - // IdxT* cols = new IdxT[nnz_]; - // RealT* vals = new RealT[nnz_]; - - // std::copy(jac.getColData(), jac.getColData() + nnz_, cols); - // std::copy(jac.getValues(), jac.getValues() + nnz_, vals); - - // // Create the CSR Jacobian - // csr_jac_ = new CsrMatrixT(size_, size_, nnz_, &row_ptrs, &cols, &vals); - - // const IdxT* map_to_sorted = jac.getMapToSorted(); - // const IdxT* map_to_dedup = jac.getMapToDeduplicated(); - - // // Build a mappping from original COO index to CSR index - // map_to_csr_ = new IdxT[nnz_dup]; - // for (IdxT i = 0; i < nnz_dup; ++i) - // { - // map_to_csr_[map_to_sorted[i]] = map_to_dedup[i]; - // } + } + + // Allocate COO triplet arrays (we own these until we hand off to CsrMatrix) + IdxT* rows_dup = new IdxT[nnz_dup]; + IdxT* cols_dup = new IdxT[nnz_dup]; + RealT* vals_dup = new RealT[nnz_dup]; + + IdxT counter = 0; + + for (const component_type* component : components_) + { + const IdxT* r = component->jacobianCooRows(); + const IdxT* c = component->jacobianCooCols(); + const RealT* v = component->jacobianCooValues(); + const IdxT nnz = component->nnz(); + + for (IdxT i = 0; i < nnz; ++i) + { + const IdxT row = component->getNodeConnection(r[i]); + const IdxT col = component->getNodeConnection(c[i]); + + if (!isValidEntry(row, col)) + { + continue; + } + + rows_dup[counter] = row; + cols_dup[counter] = col; + vals_dup[counter] = v[i]; + + ++counter; + } + } + + // Build the system COO Jacobian + LinearAlgebra::CooMatrix jac(size_, size_, nnz_dup, &rows_dup, &cols_dup, &vals_dup); + + // Populate CSR data with sort and deduplicate + IdxT* row_ptrs = jac.getCsrRowData(); + + // Deduplicated nnz + nnz_ = jac.getNnz(); + + // Allocate cols/vals with deduplicated nnz + IdxT* cols = new IdxT[nnz_]; + RealT* vals = new RealT[nnz_]; + + std::copy(jac.getColData(), jac.getColData() + nnz_, cols); + std::copy(jac.getValues(), jac.getValues() + nnz_, vals); + + // Create the CSR Jacobian + csr_jac_ = new CsrMatrixT(size_, size_, nnz_, &row_ptrs, &cols, &vals); + + const IdxT* map_to_sorted = jac.getMapToSorted(); + const IdxT* map_to_dedup = jac.getMapToDeduplicated(); + + // Build a mappping from original COO index to CSR index + map_to_csr_ = new IdxT[nnz_dup]; + for (IdxT i = 0; i < nnz_dup; ++i) + { + map_to_csr_[map_to_sorted[i]] = map_to_dedup[i]; + } return 0; } @@ -241,6 +258,21 @@ namespace GridKit */ int distributeVectors() { + + if (forcing_function_) + { + const auto forcing = (*forcing_function_)(time_); + + const auto& y_forcing = forcing.first; + const auto& yp_forcing = forcing.second; + + assert(y_forcing.size() == y_ext_.size()); + assert(yp_forcing.size() == yp_ext_.size()); + + std::copy(y_forcing.begin(), y_forcing.end(), y_ext_.begin()); + std::copy(yp_forcing.begin(), yp_forcing.end(), yp_ext_.begin()); + } + for (component_type* component : components_) { std::vector& y = component->y(); @@ -249,20 +281,22 @@ namespace GridKit for (size_t j : externals) { - if (component->getNodeConnection(j) == neg1_) + IdxT local_idx = component->getNodeConnection(j); + + if (local_idx == neg1_) { y[j] = 0.0; yp[j] = 0.0; } - else if (component->getNodeConnection(j) < this->getInternalSize()) + else if (local_idx < this->getInternalSize()) { - y[j] = y_[component->getNodeConnection(j)]; - yp[j] = yp_[component->getNodeConnection(j)]; + y[j] = y_[local_idx]; + yp[j] = yp_[local_idx]; } else { - y[j] = y_ext_[component->getNodeConnection(j) - this->getInternalSize()]; - yp[j] = yp_ext_[component->getNodeConnection(j) - this->getInternalSize()]; + y[j] = y_ext_[local_idx - this->getInternalSize()]; + yp[j] = yp_ext_[local_idx - this->getInternalSize()]; } } } @@ -284,6 +318,9 @@ namespace GridKit for (IdxT i = 0; i < this->getInternalSize(); i++) { f_[i] = 0.0; + + if (use_neumaier_sum) + neumaier_compensation[i] = 0.0; } this->distributeVectors(); @@ -311,10 +348,19 @@ namespace GridKit //@todo should do a different grounding check if (component->getNodeConnection(j) != neg1_ && component->getNodeConnection(j) < this->getInternalSize()) { - f_[component->getNodeConnection(j)] += residual[j]; + if (!use_neumaier_sum) + { + f_[component->getNodeConnection(j)] += residual[j]; + } + else + { + getNeumaierCompensation(f_[component->getNodeConnection(j)], residual[j], component->getNodeConnection(j)); + } } } } + if (use_neumaier_sum) + addNeumaierCompensation(f_); return 0; } @@ -358,16 +404,18 @@ namespace GridKit for (IdxT i = 0; i < nnz; ++i) { - if(component->getNodeConnection(r[i]) >= this->getInternalSize() && component->getNodeConnection(c[i]) >= this->getInternalSize()) + const IdxT row = component->getNodeConnection(r[i]); + const IdxT col = component->getNodeConnection(c[i]); + + const bool is_internal_entry = row != neg1_ && col != neg1_ && row < n_intern_ && col < n_intern_; + + if (!is_internal_entry) { continue; } - if (component->getNodeConnection(r[i]) != neg1_ && component->getNodeConnection(c[i]) != neg1_) - { - vals[map_to_csr_[counter]] += v[i]; - ++counter; - } + vals[map_to_csr_[counter]] += v[i]; + ++counter; } } @@ -431,27 +479,6 @@ namespace GridKit alpha_ = a; } - /** - * @brief print the system residual in COO format - * - * @param[in] filename - * @param[in] title - */ - void printResidualMatrixMarket(std::string filename, std::string title) - { - writeVectorToMatrixMarket(f_, filename, title); - } - - /** - * @brief print the system Jacobian in COO format - * - * @param[in] filename - * @param[in] title - */ - void printJacobianMatrixMarket(std::string filename, std::string title) - { - } - CsrMatrixT* getCsrJacobian() const override { return csr_jac_; @@ -589,6 +616,43 @@ namespace GridKit return f_ext_; } + void setTimeFunction(TimeFunction function) + { + forcing_function_ = std::move(function); + } + + void getNeumaierCompensation(ScalarT& sum, const ScalarT& x, const IdxT& index) + { + ScalarT t = sum + x; + if (std::abs(sum) >= std::abs(x)) + { + neumaier_compensation[index] += (sum - t) + x; + } + else + { + neumaier_compensation[index] += (x - t) + sum; + } + sum = t; + } + + void addNeumaierCompensation(std::vector& f) + { + for (IdxT i = 0; i < this->f_.size(); i++) + { + f[i] += neumaier_compensation[i]; + } + } + + std::unordered_map& getInternalMap() + { + return internal_map_; + } + + std::unordered_map& getExternalMap() + { + return external_map_; + } + private: static constexpr IdxT neg1_ = INVALID_INDEX; @@ -597,10 +661,15 @@ namespace GridKit std::unordered_map internal_map_; std::unordered_map external_map_; std::vector external_indices_; - bool root_; - std::vector y_ext_; - std::vector yp_ext_; - std::vector f_ext_; + + bool use_neumaier_sum{false}; + + std::vector neumaier_compensation; + std::vector y_ext_; + std::vector yp_ext_; + std::vector f_ext_; + + std::optional forcing_function_; IdxT* map_to_csr_{nullptr}; CsrMatrixT* csr_jac_{nullptr}; diff --git a/GridKit/Solver/Dynamic/MultiStageCosimulation.cpp b/GridKit/Solver/Dynamic/MultiStageCosimulation.cpp index 9ce53ab3c..7b1803bca 100644 --- a/GridKit/Solver/Dynamic/MultiStageCosimulation.cpp +++ b/GridKit/Solver/Dynamic/MultiStageCosimulation.cpp @@ -189,4 +189,4 @@ namespace Integrator return 0; } -} // namespace Integrator \ No newline at end of file +} // namespace Integrator diff --git a/examples/PowerElectronics/Partition/CMakeLists.txt b/examples/PowerElectronics/Partition/CMakeLists.txt index cdb522167..6f2f633d6 100644 --- a/examples/PowerElectronics/Partition/CMakeLists.txt +++ b/examples/PowerElectronics/Partition/CMakeLists.txt @@ -1,25 +1,26 @@ - find_package(OpenMP REQUIRED) add_executable(partition Partition.cpp) -target_link_libraries(partition GridKit::solvers_dyn - GridKit::power_elec_partition_interfaces) - +target_link_libraries( + partition GridKit::solvers_dyn GridKit::power_elec_partition_interfaces) add_executable(partitionMicrogrid PartitionMicrogrid.cpp) -target_link_libraries(partitionMicrogrid GridKit::power_elec_disgen - GridKit::power_elec_microline - GridKit::power_elec_microload - GridKit::solvers_dyn - GridKit::power_elec_microbusdq - GridKit::power_elec_partition_interfaces) - +target_link_libraries( + partitionMicrogrid + GridKit::power_elec_disgen + GridKit::power_elec_microline + GridKit::power_elec_microload + GridKit::solvers_dyn + GridKit::power_elec_microbusdq + GridKit::power_elec_partition_interfaces) add_executable(PartitionScaleMicrogrid PartitionScaleMicrogrid.cpp) -target_link_libraries(PartitionScaleMicrogrid GridKit::power_elec_disgen - GridKit::power_elec_microline - GridKit::power_elec_microload - GridKit::solvers_dyn - GridKit::power_elec_microbusdq - GridKit::power_elec_partition_interfaces - OpenMP::OpenMP_CXX) +target_link_libraries( + PartitionScaleMicrogrid + GridKit::power_elec_disgen + GridKit::power_elec_microline + GridKit::power_elec_microload + GridKit::solvers_dyn + GridKit::power_elec_microbusdq + GridKit::power_elec_partition_interfaces + OpenMP::OpenMP_CXX) diff --git a/examples/PowerElectronics/Partition/HiresBus.hpp b/examples/PowerElectronics/Partition/HiresBus.hpp index eeb7f6080..ae834aaba 100644 --- a/examples/PowerElectronics/Partition/HiresBus.hpp +++ b/examples/PowerElectronics/Partition/HiresBus.hpp @@ -114,4 +114,4 @@ namespace GridKit return 0; } }; -} // namespace GridKit \ No newline at end of file +} // namespace GridKit diff --git a/examples/PowerElectronics/Partition/Partition.cpp b/examples/PowerElectronics/Partition/Partition.cpp index 319e4dc00..acd56914f 100644 --- a/examples/PowerElectronics/Partition/Partition.cpp +++ b/examples/PowerElectronics/Partition/Partition.cpp @@ -1,11 +1,15 @@ #include +#include "GridKit/LinearAlgebra/DenseMatrix/DenseMatrix.hpp" + #define _USE_MATH_DEFINES #include #include +#include #include #include +#include #include #include @@ -15,9 +19,21 @@ std::vector hires(const std::vector& y, const std::vector& yp); +template +int jac_hires(const std::vector& y, [[maybe_unused]] const std::vector& yp, GridKit::LinearAlgebra::DenseMatrix& jac, RealT alpha); + +template +void addCsrToDense( + GridKit::LinearAlgebra::CsrMatrix* csr, + GridKit::LinearAlgebra::DenseMatrix& dense, + GridKit::SubsystemModel* partition); + int main(int /* argc */, char const** /* argv */) { + using Bus = GridKit::PowerElectronics::MicrogridBus; + Bus bus; + GridKit::SubsystemModel* partition1 = new GridKit::SubsystemModel(); GridKit::SubsystemModel* partition2 = new GridKit::SubsystemModel(); @@ -25,6 +41,15 @@ int main(int /* argc */, char const** /* argv */) GridKit::HiresBus* bus1 = new GridKit::HiresBus(2); GridKit::HiresComponent3* comp3 = new GridKit::HiresComponent3(3); + bus.allocate(); + + bus.setExternalConnectionNodes(0, 3); + bus.setExternalConnectionNodes(1, 4); + + comp1->allocate(); + comp3->allocate(); + bus1->allocate(); + comp1->setExternalConnectionNodes(0, 3); comp1->setExternalConnectionNodes(1, 4); comp1->setExternalConnectionNodes(2, 0); @@ -40,15 +65,19 @@ int main(int /* argc */, char const** /* argv */) comp3->setExternalConnectionNodes(3, 6); comp3->setExternalConnectionNodes(4, 7); - GridKit::HiresComponent3 comp3copy(*comp3); - GridKit::BusPartitionInterface* busInterface = new GridKit::BusPartitionInterface(comp3copy, 3, 4, 4); + GridKit::HiresComponent3 + comp3copy(*comp3); + GridKit::BusPartitionInterface* busInterface = new GridKit::BusPartitionInterface(bus, comp3copy, 4); + busInterface->allocate(); partition1->addComponent(comp1); partition1->addComponent(bus1); partition1->addComponent(busInterface); + partition1->addNode(&bus); partition2->addComponent(comp3); + std::cout << "Msg" << std::endl; partition1->allocate(); partition2->allocate(); @@ -117,6 +146,42 @@ int main(int /* argc */, char const** /* argv */) printf("%-10.5g ---------- %10zu\n", ref[i], i); } + partition1->updateTime(0, 1.0); + partition2->updateTime(0, 1.0); + + partition1->evaluateJacobian(); + partition2->evaluateJacobian(); + + GridKit::LinearAlgebra::DenseMatrix jac1(8, 8); + GridKit::LinearAlgebra::DenseMatrix jac2(8, 8); + + GridKit::LinearAlgebra::DenseMatrix jac_ref(8, 8); + + addCsrToDense(partition1->getCsrJacobian(), jac1, partition1); + addCsrToDense(partition2->getCsrJacobian(), jac2, partition2); + jac_hires(y, yp, jac_ref, 1.0); + + auto print_dense = [&](GridKit::LinearAlgebra::DenseMatrix& jc) -> void + { + for (size_t i = 0; i < 8; ++i) + { + for (size_t j = 0; j < 8; ++j) + { + std::cout << std::setw(10) << jc.getValue(i, j) << ' '; + } + std::cout << '\n'; + } + std::cout << '\n'; + }; + + print_dense(jac1); + print_dense(jac2); + print_dense(jac_ref); + + delete comp1; + delete bus1; + delete busInterface; + delete comp3; delete partition1; delete partition2; } @@ -125,14 +190,82 @@ std::vector hires(const std::vector& y, const std::vector f(8); - f[0] = yp[0] + 1.71 * y[0] - 0.43 * y[1] - 8.32 * y[2] - 0.0007; - f[1] = yp[1] - 1.71 * y[0] + 8.75 * y[1]; - f[2] = yp[2] + 10.03 * y[2] - 0.43 * y[3] - 0.035 * y[4]; - f[3] = yp[3] - 8.32 * y[1] - 1.71 * y[2] + 1.12 * y[3]; - f[4] = yp[4] + 1.745 * y[4] - 0.43 * y[5] - 0.43 * y[6]; - f[5] = yp[5] + 280 * y[5] * y[7] - 0.69 * y[3] - 1.71 * y[4] + 0.43 * y[5] - 0.69 * y[6]; - f[6] = yp[6] - 280 * y[5] * y[7] + 1.81 * y[6]; - f[7] = yp[7] + 280 * y[5] * y[7] - 1.81 * y[6]; + f[0] = -yp[0] - 1.71 * y[0] + 0.43 * y[1] + 8.32 * y[2] + 0.0007; + f[1] = -yp[1] + 1.71 * y[0] - 8.75 * y[1]; + f[2] = -yp[2] - 10.03 * y[2] + 0.43 * y[3] + 0.035 * y[4]; + f[3] = -yp[3] + 8.32 * y[1] + 1.71 * y[2] - 1.12 * y[3]; + f[4] = -yp[4] - 1.745 * y[4] + 0.43 * y[5] + 0.43 * y[6]; + f[5] = -yp[5] - 280 * y[5] * y[7] + 0.69 * y[3] + 1.71 * y[4] - 0.43 * y[5] + 0.69 * y[6]; + f[6] = -yp[6] + 280 * y[5] * y[7] - 1.81 * y[6]; + f[7] = -yp[7] - 280 * y[5] * y[7] + 1.81 * y[6]; return f; } + +template +int jac_hires(const std::vector& y, [[maybe_unused]] const std::vector& yp, GridKit::LinearAlgebra::DenseMatrix& jac, RealT alpha) +{ + + jac.setValue(0, 0, -alpha - 1.71); + jac.setValue(0, 1, 0.43); + jac.setValue(0, 2, 8.32); + + jac.setValue(1, 0, 1.71); + jac.setValue(1, 1, -alpha - 8.75); + + jac.setValue(2, 2, -alpha - 10.03); + jac.setValue(2, 3, 0.43); + jac.setValue(2, 4, 0.035); + + jac.setValue(3, 1, 8.32); + jac.setValue(3, 2, 1.71); + jac.setValue(3, 3, -alpha - 1.12); + + jac.setValue(4, 4, -alpha - 1.745); + jac.setValue(4, 5, 0.43); + jac.setValue(4, 6, 0.43); + + jac.setValue(5, 3, 0.69); + jac.setValue(5, 4, 1.71); + jac.setValue(5, 5, -alpha - 280.0 * y[7] - 0.43); + jac.setValue(5, 6, 0.69); + jac.setValue(5, 7, -280.0 * y[5]); + + jac.setValue(6, 5, 280.0 * y[7]); + jac.setValue(6, 6, -alpha - 1.81); + jac.setValue(6, 7, 280.0 * y[5]); + + jac.setValue(7, 5, -280.0 * y[7]); + jac.setValue(7, 6, 1.81); + jac.setValue(7, 7, -alpha - 280.0 * y[5]); + + return 0; +} + +template +void addCsrToDense( + GridKit::LinearAlgebra::CsrMatrix* csr, + GridKit::LinearAlgebra::DenseMatrix& dense, + GridKit::SubsystemModel* partition) +{ + auto* row_ptr = csr->getRowData(GridKit::LinearAlgebra::memory::HOST); + auto* col_ind = csr->getColData(GridKit::LinearAlgebra::memory::HOST); + auto* values = csr->getValues(GridKit::LinearAlgebra::memory::HOST); + + assert(row_ptr != nullptr); + assert(col_ind != nullptr); + assert(values != nullptr); + + for (IdxT row = 0; row < csr->getNumRows(); ++row) + { + for (IdxT k = row_ptr[row]; k < row_ptr[row + 1]; ++k) + { + const IdxT col = col_ind[k]; + + auto r = partition->getNodeConnection(row); + auto c = partition->getNodeConnection(col); + + dense.setValue(r, c, dense.getValue(r, c) + values[k]); + } + } +} diff --git a/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp b/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp index ff3d23a5d..460b8ba67 100644 --- a/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp +++ b/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp @@ -1,8 +1,8 @@ -#include + #include #include #include -#include +#include #include #define _USE_MATH_DEFINES @@ -21,6 +21,8 @@ #include #include +#include "jac_test_helper.hpp" + int main() { /// @todo Needs to be modified. Some components are small relative to others thus @@ -29,7 +31,6 @@ int main() double rel_tol = 1.0e-8; size_t max_step_number = 3000; bool use_jac = true; - bool debug_output = true; // Create model auto* sysmodel = new GridKit::PowerElectronicsModel(rel_tol, abs_tol, use_jac, max_step_number); @@ -191,7 +192,6 @@ int main() partition2->addComponent(dg4); partition2->addComponent(l2); partition2->addComponent(l3); - partition2->addComponent(load2); partition2->addComponent(bus_para_4); partition2->addComponent(bus_para_3); @@ -213,60 +213,51 @@ int main() sysmodel->yp()[i] = yp[i]; } + sysmodel->updateTime(2, 5); sysmodel->evaluateResidual(); - std::vector f_sysmodel = sysmodel->getResidual(); + sysmodel->evaluateJacobian(); - partition1->allocate(); - partition2->allocate(); + auto full_jac = sysmodel->getCsrJacobian(); + + std::vector f_sysmodel = sysmodel->getResidual(); std::vector*> partitions = {partition1, partition2}; // Distribute externals to partition 1 for (auto* partition : partitions) { + partition->allocate(); + + partition->updateTime(2, 5); + for (size_t i = 0; i < partition->getExternSize(); i++) { partition->getExternalDataY()[i] = y[partition->getExternalIndices()[i]]; partition->getExternalDataYP()[i] = yp[partition->getExternalIndices()[i]]; } - } - for (auto* partition : partitions) - { for (size_t i = 0; i < partition->getInternalSize(); i++) { partition->y()[i] = y[partition->getNodeConnection(i)]; partition->yp()[i] = yp[partition->getNodeConnection(i)]; } - } - for (auto* partition : partitions) - { partition->evaluateResidual(); + partition->evaluateJacobian(); } - auto printTitle = [](std::string msg) -> void - { - std::cout << "\n--------------- " << msg << " -------------" << std::endl; - printf("%-12s ---------- %12s\n", "Res Values", "Comp. Index"); - }; + auto partition1_jac = partition1->getCsrJacobian(); + auto partition2_jac = partition2->getCsrJacobian(); - // Print Residuals from partition 1 - int counter = 1; - for (auto* partition : partitions) - { - printTitle("Partition " + std::to_string(counter++)); - for (size_t i = 0; i < partition->getInternalSize(); i++) - { - auto com_index = partition->getNodeConnection(static_cast(i)); - printf("%-12.5g ---------- %7zu\n", partition->getResidual()[i], com_index); - } - } + bool jac_matched_1 = GridKit::Testing::verifySubsystemJacobian(*full_jac, *partition1_jac, *partition1); + bool jac_matched_2 = GridKit::Testing::verifySubsystemJacobian(*full_jac, *partition2_jac, *partition2); - printTitle("Reference Solution"); - for (size_t i = 0; i < sysmodel->size(); i++) + std::cout << "Jacobian Matched: " << jac_matched_1 * jac_matched_2 << std::endl; + + if (!jac_matched_1 || !jac_matched_2) { - printf("%-12.5g ---------- %7zu\n", sysmodel->getResidual()[i], i); + std::cout << "ERROR: At least one subsystem Jacobian is incorrect!" << std::endl; + return 1; } std::vector f(sysmodel->size(), 0.0); @@ -281,24 +272,27 @@ int main() } } - for (size_t i = 0; i < sysmodel->size(); i++) - { - error[i] = f_sysmodel[i] - f[i]; - std::cout << error[i] << std::endl; - } - double max_error = 0; for (size_t i = 0; i < sysmodel->size(); i++) { + error[i] = (f_sysmodel[i] - f[i]) / f_sysmodel[i]; if (max_error < std::abs(error[i])) { max_error = std::abs(error[i]); } } + if (max_error > std::numeric_limits::epsilon()) + { + std::cout << "ERROR: Max Error too high!" << std::endl; + return 1; + } + std::cout << "\nMax Error of Reference and Partition Evaluation: " << max_error << std::endl; delete sysmodel; + delete partition1; + delete partition2; return 0; -} \ No newline at end of file +} diff --git a/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp b/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp index 4e59848c8..a27f0092a 100644 --- a/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp +++ b/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp @@ -4,7 +4,9 @@ #include #include #include +#include #include +#include #include #include @@ -19,6 +21,8 @@ #include #include +#include "jac_test_helper.hpp" + /****************************************************************************** * Partitioned Residual Evaluation * @@ -44,11 +48,13 @@ using real_type = double; struct RunResult { - index_type num_partitions; - real_type partition_time; // seconds - real_type monolithic_time; // seconds - real_type speedup; // monolithic / partition - real_type max_error; + bool success = true; + index_type num_partitions; + real_type partition_time; // seconds + real_type monolithic_time; // seconds + real_type speedup; // monolithic / partition + real_type max_error; + std::string subsys_jac; }; RunResult printMicrogridSystems(index_type N_size, index_type num_partitions); @@ -64,14 +70,15 @@ int main() { index_type N_size = 5000; - std::cout << std::format("{:<16}{:>16}{:>18}{:>12}{:>14}\n", + std::cout << std::format("{:<16}{:>16}{:>18}{:>12}{:>14}{:>16}\n", "num_partitions", "partition_time", "monolithic_time", "speedup", - "error"); + "error", + "Jacobians"); - std::cout << std::string(76, '-') << "\n"; + std::cout << std::string(93, '-') << "\n"; for (index_type p : {10, 48, 100, 500, 1000, 2000, 5000}) { @@ -79,12 +86,18 @@ int main() RunResult r = printMicrogridSystems(N_size, p); - std::cout << std::format("{:<16d}{:>14.4f} s{:>16.4f} s{:>11.2f}x{:>14.3e}\n", + if (!r.success) + { + return 1; + } + + std::cout << std::format("{:<16d}{:>14.4f} s{:>16.4f} s{:>11.2f}x{:>14.3e} {:>16s}\n", r.num_partitions, r.partition_time, r.monolithic_time, r.speedup, - r.max_error); + r.max_error, + r.subsys_jac); } return 0; @@ -319,12 +332,16 @@ RunResult printMicrogridSystems(index_type N_size, index_type num_partitions) sys_model_control->yp()[i] = yp[i]; } + sys_model_control->updateTime(2, 5); sys_model_control->evaluateResidual(); auto end_time = std::chrono::high_resolution_clock::now(); auto monolithic_time = std::chrono::duration(end_time - start_time); + sys_model_control->evaluateJacobian(); + auto& f_sysmodel_control = sys_model_control->getResidual(); + auto* full_jac = sys_model_control->getCsrJacobian(); //--------------------------------------------------------------- // Partition the monolithic network into independent subsystem @@ -343,7 +360,7 @@ RunResult printMicrogridSystems(index_type N_size, index_type num_partitions) index_type index = 0; for (index_type j = 0; j < num_partitions; j++) { - auto* partition = new SubsystemModel(false); + auto* partition = new SubsystemModel(); // add Reference rotor to the first partition if (j == 0) @@ -404,6 +421,7 @@ RunResult printMicrogridSystems(index_type N_size, index_type num_partitions) for (auto* partition : subsystems) { partition->allocate(); + partition->updateTime(2, 5); } start_time = std::chrono::high_resolution_clock::now(); @@ -447,6 +465,18 @@ RunResult printMicrogridSystems(index_type N_size, index_type num_partitions) // roundoff. //--------------------------------------------------------------- + bool matched = true; + + for (auto* partition : subsystems) + { + partition->evaluateJacobian(); + + matched &= GridKit::Testing::verifySubsystemJacobian( + *full_jac, + *partition->getCsrJacobian(), + *partition); + } + real_type max_error = 0; for (size_t i = 0; i < sys_model_control->size(); i++) { @@ -464,6 +494,19 @@ RunResult printMicrogridSystems(index_type N_size, index_type num_partitions) result.monolithic_time = monolithic_time.count(); result.speedup = monolithic_time.count() / partition_time.count(); result.max_error = max_error; + result.subsys_jac = matched ? "Correct" : "Wrong"; + + if (!matched) + { + std::cout << "ERROR: At least one subsystem Jacobian is incorrect!" << std::endl; + result.success = false; + } + + if (max_error > std::numeric_limits::epsilon()) + { + std::cout << "ERROR: Max Error too high!" << std::endl; + result.success = false; + } for (auto* linescpy : linesCopies) delete linescpy; @@ -474,4 +517,4 @@ RunResult printMicrogridSystems(index_type N_size, index_type num_partitions) delete sys_model_control; return result; -} \ No newline at end of file +} diff --git a/examples/PowerElectronics/Partition/jac_test_helper.hpp b/examples/PowerElectronics/Partition/jac_test_helper.hpp new file mode 100644 index 000000000..10daf9631 --- /dev/null +++ b/examples/PowerElectronics/Partition/jac_test_helper.hpp @@ -0,0 +1,250 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace GridKit +{ + namespace Testing + { + + template + bool verifySubsystemJacobian( + GridKit::LinearAlgebra::CsrMatrix& full_jac, + GridKit::LinearAlgebra::CsrMatrix& sub_jac, + GridKit::SubsystemModel& subsystem, + RealT tolerance = static_cast(1e-12)) + { + constexpr auto host = GridKit::LinearAlgebra::memory::HOST; + + // Full-system CSR data. + const IdxT* full_rows = full_jac.getRowData(host); + const IdxT* full_cols = full_jac.getColData(host); + const RealT* full_vals = full_jac.getValues(host); + + // Subsystem CSR data. + const IdxT* sub_rows = sub_jac.getRowData(host); + const IdxT* sub_cols = sub_jac.getColData(host); + const RealT* sub_vals = sub_jac.getValues(host); + + const IdxT num_sub_rows = sub_jac.getNumRows(); + const IdxT num_sub_cols = sub_jac.getNumColumns(); + + /* + * The subsystem internal map stores: + * + * global index -> local index + */ + const auto& global_to_local = subsystem.getInternalMap(); + + if (global_to_local.size() != num_sub_rows) + { + std::cout << "Internal map size mismatch: map has " + << global_to_local.size() + << " entries, but subsystem Jacobian has " + << num_sub_rows + << " rows\n"; + + return false; + } + + if (num_sub_rows != num_sub_cols) + { + std::cout << "Subsystem Jacobian is not square: " + << num_sub_rows + << " rows and " + << num_sub_cols + << " columns\n"; + + return false; + } + + /* + * Build the reverse mapping: + * + * local index -> global index + * + * This is needed because the subsystem Jacobian stores local row + * and column indices. + */ + std::vector local_to_global(num_sub_rows); + std::vector local_index_found(num_sub_rows, false); + + for (const auto& [global_index, local_index] : global_to_local) + { + + if (global_index >= full_jac.getNumRows()) + { + std::cout << "Invalid global index " + << global_index + << " in subsystem internal map\n"; + + return false; + } + + if (local_index >= num_sub_rows) + { + std::cout << "Invalid local index " + << local_index + << " mapped from global index " + << global_index << '\n'; + + return false; + } + + if (local_index_found[local_index]) + { + std::cout << "Duplicate local index " + << local_index + << " in subsystem internal map\n"; + + return false; + } + + local_to_global[local_index] = global_index; + local_index_found[local_index] = true; + } + + // Verify that every local index has a corresponding global index. + for (IdxT local_index = 0; local_index < num_sub_rows; ++local_index) + { + if (!local_index_found[local_index]) + { + std::cout << "No global index maps to local index " + << local_index << '\n'; + + return false; + } + } + + bool matches = true; + + /* + * Compare each subsystem row against the corresponding full-system row. + */ + for (IdxT local_row = 0; local_row < num_sub_rows; ++local_row) + { + const IdxT global_row = local_to_global[local_row]; + + const IdxT sub_begin = sub_rows[local_row]; + const IdxT sub_end = sub_rows[local_row + 1]; + const IdxT full_begin = full_rows[global_row]; + const IdxT full_end = full_rows[global_row + 1]; + + /* + * Store this subsystem row using global column indices. + * + * The subsystem CSR row is sorted by local column index. After + * converting local columns to global columns, the global columns + * may no longer be sorted. Therefore, we use a lookup map instead + * of comparing both CSR rows sequentially. + */ + std::unordered_map sub_row_entries; + + for (IdxT sub_index = sub_begin; sub_index < sub_end; ++sub_index) + { + const IdxT local_column = sub_cols[sub_index]; + + if (local_column >= num_sub_cols) + { + std::cout << "Invalid subsystem column index " + << local_column + << " in local row " + << local_row << '\n'; + + matches = false; + continue; + } + + const IdxT global_column = local_to_global[local_column]; + + // Check for duplicate columns in this subsystem row. + if (sub_row_entries.find(global_column) != sub_row_entries.end()) + { + std::cout << "Duplicate subsystem entry at (" + << global_row << ", " + << global_column << ")\n"; + + matches = false; + continue; + } + + sub_row_entries[global_column] = sub_vals[sub_index]; + } + + /* + * Compare every full-system entry whose column belongs to this + * subsystem. + */ + for (IdxT full_index = full_begin; + full_index < full_end; + ++full_index) + { + const IdxT global_column = full_cols[full_index]; + + // Ignore columns owned by another subsystem. + if (global_to_local.find(global_column) == global_to_local.end()) + { + continue; + } + + auto sub_entry = sub_row_entries.find(global_column); + + if (sub_entry == sub_row_entries.end()) + { + std::cout << "Entry exists only in full Jacobian at (" + << global_row << ", " + << global_column << ")\n"; + + matches = false; + continue; + } + + const RealT full_value = full_vals[full_index]; + const RealT sub_value = sub_entry->second; + const RealT difference = std::abs(full_value - sub_value); + + if (difference > tolerance) + { + std::cout << "Jacobian value mismatch at (" + << global_row << ", " + << global_column << "): " + << "full = " << full_value + << ", subsystem = " << sub_value + << ", difference = " << difference << '\n'; + + matches = false; + } + + /* + * Remove the matched subsystem entry. + * + * After the full row has been checked, any remaining entries + * exist only in the subsystem Jacobian. + */ + sub_row_entries.erase(sub_entry); + } + + // Report subsystem entries that were not found in the full Jacobian. + for (const auto& entry : sub_row_entries) + { + const IdxT global_column = entry.first; + + std::cout << "Entry exists only in subsystem Jacobian at (" + << global_row << ", " + << global_column << ")\n"; + + matches = false; + } + } + + return matches; + } + + } // namespace Testing +} // namespace GridKit From def6655d4571438c6989fb3e967f0dcf8cfa6da0 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Sun, 19 Jul 2026 08:26:03 +0000 Subject: [PATCH 23/34] Update partitioning code to work with recent changes in develop --- .../PowerElectronics/CircuitComponent.hpp | 126 ++++- .../BusPartitionInterface.cpp | 55 +- .../BusPartitionInterface.hpp | 8 +- .../PartitionInterface/PartitionInterface.hpp | 4 - .../Model/PowerElectronics/SubsystemModel.hpp | 156 +++--- .../PowerElectronics/Partition/Partition.cpp | 501 +++++++++--------- .../Partition/PartitionMicrogrid.cpp | 42 +- .../Partition/PartitionScaleMicrogrid.cpp | 44 +- .../Partition/jac_test_helper.hpp | 10 +- 9 files changed, 573 insertions(+), 373 deletions(-) diff --git a/GridKit/Model/PowerElectronics/CircuitComponent.hpp b/GridKit/Model/PowerElectronics/CircuitComponent.hpp index 026db4df8..a7c462d76 100644 --- a/GridKit/Model/PowerElectronics/CircuitComponent.hpp +++ b/GridKit/Model/PowerElectronics/CircuitComponent.hpp @@ -26,6 +26,130 @@ 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); + + const int error_code = destination.copyFromExternal(source); + assert(error_code == 0); + }; + + /* + * Deep-copy the local-to-global connection mapping. + */ + if (other.connection_nodes_) + { + connection_nodes_ = + std::make_unique(static_cast(size_)); + + for (IdxT i = 0; i < size_; ++i) + { + connection_nodes_[static_cast(i)] = + other.connection_nodes_[static_cast(i)]; + } + } + + /* + * Deep-copy the COO Jacobian row indices. + */ + if (other.jacobian_coo_rows_) + { + jacobian_coo_rows_ = + std::make_unique(static_cast(nnz_)); + + for (IdxT i = 0; i < nnz_; ++i) + { + jacobian_coo_rows_[static_cast(i)] = + other.jacobian_coo_rows_[static_cast(i)]; + } + } + + /* + * Deep-copy the COO Jacobian column indices. + */ + if (other.jacobian_coo_cols_) + { + jacobian_coo_cols_ = + std::make_unique(static_cast(nnz_)); + + for (IdxT i = 0; i < nnz_; ++i) + { + jacobian_coo_cols_[static_cast(i)] = + other.jacobian_coo_cols_[static_cast(i)]; + } + } + + /* + * Deep-copy the COO Jacobian values. + */ + if (other.jacobian_coo_values_) + { + jacobian_coo_values_ = + std::make_unique(static_cast(nnz_)); + + for (IdxT i = 0; i < nnz_; ++i) + { + jacobian_coo_values_[static_cast(i)] = + other.jacobian_coo_values_[static_cast(i)]; + } + } + + // 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_); + + // Quadrature vector. + copyVector(g_, other.g_); + + // Adjoint vectors. + copyVector(yB_, other.yB_); + copyVector(ypB_, other.ypB_); + copyVector(fB_, other.fB_); + copyVector(gB_, other.gB_); + + // Parameter vectors. + copyVector(param_, other.param_); + copyVector(param_up_, other.param_up_); + copyVector(param_lo_, other.param_lo_); + } + /** * @note Cannot be marked final, since it is overriden to recurse in the system model. */ @@ -50,7 +174,7 @@ namespace GridKit return this->n_intern_; } - std::set getExternIndices() + std::set getExternIndices() { return this->extern_indices_; } diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp index 85d8d43fb..070c190f6 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp @@ -76,11 +76,8 @@ namespace GridKit CircuitComponent::allocate(); - y_.resize(static_cast(size_)); - yp_.resize(static_cast(size_)); - f_.resize(static_cast(size_)); + std::fill_n(f_.getData(), size_, 0); - std::fill(f_.begin(), f_.end(), 0); bool port_i_set = false; bool port_j_set = false; @@ -123,6 +120,13 @@ namespace GridKit return 0; } + template + int BusPartitionInterface::setAbsoluteTolerance(RealT rel_tol) + { + abs_tol_.setToConst(static_cast(rel_tol)); + return 0; + } + /** * Initialization of the grid model */ @@ -150,43 +154,48 @@ namespace GridKit return 0; } - /** - * @brief Eval Micro Load - */ template int BusPartitionInterface::evaluateExternalResidual() { - size_t internal = 0; size_t external = 0; + ScalarT* y = y_.getData(); + ScalarT* yp = yp_.getData(); + ScalarT* f = f_.getData(); + + ScalarT* component_y = component_.y().getData(); + ScalarT* component_yp = component_.yp().getData(); + const auto& extern_indices = component_.getExternIndices(); - for (IdxT i = 0; i < component_.size(); ++i) + for (size_t i = 0; i < static_cast(component_.size()); ++i) { - const bool is_external = extern_indices.contains(i); - - if (is_external) + if (extern_indices.contains(i)) { - component_.y()[external] = y_[i]; - component_.yp()[external] = yp_[i]; + component_y[external] = y[i]; + component_yp[external] = yp[i]; ++external; - continue; } - - y_ptr[internal] = y_[i]; - yp_ptr[internal] = yp_[i]; - ++internal; + else + { + y_ptr[internal] = y[i]; + yp_ptr[internal] = yp[i]; + ++internal; + } } - component_.evaluateExternalResidual(); + component_.evaluateResidual(); - auto f = component_.getResidual(); + const auto* residual = component_.getResidual().getData(); // TODO: This assumes that external variables are ordered after all internal // variables in the local indexing. To make this more robust, we need to get rid of this assumption. - f_[bus_port_i_] = f[bus_port_i_]; - f_[bus_port_j_] = f[bus_port_j_]; + f[bus_port_i_] = residual[bus_port_i_]; + f[bus_port_j_] = residual[bus_port_j_]; + + f_.setDataUpdated(); + return 0; } diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp index 1bda78a89..7244fad4d 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp @@ -32,6 +32,7 @@ namespace GridKit using CircuitComponent::yp_; using CircuitComponent::yp_int_; using CircuitComponent::tag_; + using CircuitComponent::abs_tol_; using CircuitComponent::f_; using CircuitComponent::f_int_; using CircuitComponent::g_; @@ -42,13 +43,13 @@ namespace GridKit using CircuitComponent::param_; using CircuitComponent::idc_; - using PartitionInterface::bus_port_i_; - using PartitionInterface::bus_port_j_; - using CircuitComponent::extern_indices_; using CircuitComponent::n_extern_; using CircuitComponent::n_intern_; + using PartitionInterface::bus_port_i_; + using PartitionInterface::bus_port_j_; + public: BusPartitionInterface(node_type& bus, component_type& component, IdxT id); virtual ~BusPartitionInterface(); @@ -56,6 +57,7 @@ namespace GridKit int allocate(); int initialize(); int tagDifferentiable(); + int setAbsoluteTolerance(RealT); int evaluateInternalResidual() final; int evaluateExternalResidual() final; int evaluateJacobian(); diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp b/GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp index 1e5a3c52d..f639b0448 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/PartitionInterface.hpp @@ -25,10 +25,6 @@ namespace GridKit class PartitionInterface : public CircuitComponent { public: - using RealT = typename Model::Evaluator::RealT; - using MatrixT = typename Model::Evaluator::MatrixT; - using CsrMatrixT = typename Model::Evaluator::CsrMatrixT; - PartitionInterface() = default; ~PartitionInterface() = default; diff --git a/GridKit/Model/PowerElectronics/SubsystemModel.hpp b/GridKit/Model/PowerElectronics/SubsystemModel.hpp index 1fdb79193..cf793725e 100644 --- a/GridKit/Model/PowerElectronics/SubsystemModel.hpp +++ b/GridKit/Model/PowerElectronics/SubsystemModel.hpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include @@ -22,7 +21,6 @@ namespace GridKit class SubsystemModel : public CircuitComponent { using RealT = typename CircuitComponent::RealT; - using MatrixT = typename CircuitComponent::MatrixT; using CsrMatrixT = typename CircuitComponent::CsrMatrixT; using component_type = CircuitComponent; using node_type = PowerElectronics::NodeBase; @@ -41,9 +39,10 @@ namespace GridKit using CircuitComponent::yp_int_; using CircuitComponent::f_; using CircuitComponent::f_int_; - using CircuitComponent::rel_tol_; + using CircuitComponent::tag_; using CircuitComponent::abs_tol_; - using CircuitComponent::extern_indices_; + using CircuitComponent::allocated_; + using CircuitComponent::allocateVectors; public: /** @@ -55,11 +54,7 @@ namespace GridKit SubsystemModel() { // Set system model parameters as default - rel_tol_ = 1e-4; - abs_tol_ = 1e-4; - this->max_steps_ = 2000; - // By default don't use the jacobian - use_jac_ = false; + use_jac_ = false; } virtual ~SubsystemModel() @@ -94,15 +89,20 @@ namespace GridKit CircuitComponent::allocate(); - y_.resize(n_intern_); - yp_.resize(n_intern_); - f_.resize(n_intern_); - neumaier_compensation.resize(n_intern_); + // Allocation always rebuilds the system Jacobian and its COO-to-CSR map. + delete csr_jac_; + csr_jac_ = nullptr; + + delete[] map_to_csr_; + map_to_csr_ = nullptr; + + tag_.resize(size_); // Allocate subsystem vectors. y_ext_.resize(n_extern_); yp_ext_.resize(n_extern_); f_ext_.resize(n_extern_); + external_indices_.resize(n_extern_); // Store the mapping from local subsystem indices back to their global system indices @@ -117,13 +117,16 @@ namespace GridKit external_indices_[local_idx - n_intern_] = global_idx; } - size_t component_internal_idx = 0; + size_t component_internal_idx = 0; + const auto* y = y_.getData(); + const auto* yp = yp_.getData(); + auto* f = f_.getData(); for (component_type* comp : components_) { - comp->setInternalPointer(&y_[component_internal_idx]); - comp->setInternalDerivativePointer(&yp_[component_internal_idx]); - comp->setInternalResidualPointer(&f_[component_internal_idx]); + comp->setInternalPointer(&y[component_internal_idx]); + comp->setInternalDerivativePointer(&yp[component_internal_idx]); + comp->setInternalResidualPointer(&f[component_internal_idx]); component_internal_idx += comp->getInternalSize(); } @@ -229,6 +232,7 @@ namespace GridKit map_to_csr_[map_to_sorted[i]] = map_to_dedup[i]; } + allocated_ = true; return 0; } @@ -244,6 +248,8 @@ namespace GridKit { component->initialize(); } + y_.setDataUpdated(); + yp_.setDataUpdated(); this->distributeVectors(); return 0; @@ -273,11 +279,14 @@ namespace GridKit std::copy(yp_forcing.begin(), yp_forcing.end(), yp_ext_.begin()); } + const auto* y_system = y_.getData(); + const auto* yp_system = yp_.getData(); + for (component_type* component : components_) { - std::vector& y = component->y(); - std::vector& yp = component->yp(); - const std::set& externals = component->getExternIndices(); + auto* y = component->y().getData(); + auto* yp = component->yp().getData(); + const auto& externals = component->getExternIndices(); for (size_t j : externals) { @@ -290,8 +299,8 @@ namespace GridKit } else if (local_idx < this->getInternalSize()) { - y[j] = y_[local_idx]; - yp[j] = yp_[local_idx]; + y[j] = y_system[local_idx]; + yp[j] = yp_system[local_idx]; } else { @@ -299,6 +308,8 @@ namespace GridKit yp[j] = yp_ext_[local_idx - this->getInternalSize()]; } } + component->y().setDataUpdated(); + component->yp().setDataUpdated(); } return 0; } @@ -315,12 +326,16 @@ namespace GridKit */ int evaluateInternalResidual() final { + auto* f = f_.getData(); + for (IdxT i = 0; i < this->getInternalSize(); i++) { - f_[i] = 0.0; + f[i] = 0.0; - if (use_neumaier_sum) - neumaier_compensation[i] = 0.0; + // if (use_neumaier_sum) + // { + // neumaier_compensation[i] = 0.0; + // } } this->distributeVectors(); @@ -340,27 +355,33 @@ namespace GridKit if (int err_code = component->evaluateExternalResidual()) return err_code; - const std::vector& residual = component->getResidual(); - const std::set& externals = component->getExternIndices(); + const auto* residual = component->getResidual().getData(); + const auto& externals = component->getExternIndices(); for (size_t j : externals) { //@todo should do a different grounding check if (component->getNodeConnection(j) != neg1_ && component->getNodeConnection(j) < this->getInternalSize()) { - if (!use_neumaier_sum) - { - f_[component->getNodeConnection(j)] += residual[j]; - } - else - { - getNeumaierCompensation(f_[component->getNodeConnection(j)], residual[j], component->getNodeConnection(j)); - } + // if (!use_neumaier_sum) + // { + f[component->getNodeConnection(j)] += residual[j]; + // } + // else + // { + // getNeumaierCompensation(f_[component->getNodeConnection(j)], residual[j], component->getNodeConnection(j)); + // } } } } - if (use_neumaier_sum) - addNeumaierCompensation(f_); + + // if (use_neumaier_sum) + // { + // addNeumaierCompensation(f_); + // } + + f_.setDataUpdated(); + return 0; } @@ -420,7 +441,6 @@ namespace GridKit } jac_call_count_++; - return 0; } @@ -463,6 +483,24 @@ 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. + */ + int setAbsoluteTolerance(RealT rel_tol) final + { + abs_tol_.setToConst(static_cast(rel_tol)); + return 0; + } + /** * @brief Distribute time and time scaling for each component * @@ -621,27 +659,27 @@ namespace GridKit forcing_function_ = std::move(function); } - void getNeumaierCompensation(ScalarT& sum, const ScalarT& x, const IdxT& index) - { - ScalarT t = sum + x; - if (std::abs(sum) >= std::abs(x)) - { - neumaier_compensation[index] += (sum - t) + x; - } - else - { - neumaier_compensation[index] += (x - t) + sum; - } - sum = t; - } - - void addNeumaierCompensation(std::vector& f) - { - for (IdxT i = 0; i < this->f_.size(); i++) - { - f[i] += neumaier_compensation[i]; - } - } + // void getNeumaierCompensation(ScalarT& sum, const ScalarT& x, const IdxT& index) + // { + // ScalarT t = sum + x; + // if (std::abs(sum) >= std::abs(x)) + // { + // neumaier_compensation[index] += (sum - t) + x; + // } + // else + // { + // neumaier_compensation[index] += (x - t) + sum; + // } + // sum = t; + // } + + // void addNeumaierCompensation(VectorT f) + // { + // for (IdxT i = 0; i < size_; i++) + // { + // f[i] += neumaier_compensation[i]; + // } + // } std::unordered_map& getInternalMap() { diff --git a/examples/PowerElectronics/Partition/Partition.cpp b/examples/PowerElectronics/Partition/Partition.cpp index acd56914f..ab6d981f5 100644 --- a/examples/PowerElectronics/Partition/Partition.cpp +++ b/examples/PowerElectronics/Partition/Partition.cpp @@ -1,271 +1,270 @@ -#include - -#include "GridKit/LinearAlgebra/DenseMatrix/DenseMatrix.hpp" +// #include #define _USE_MATH_DEFINES #include #include -#include -#include -#include +// #include +// #include +// #include #include #include #include -#include "HiresBus.hpp" -#include "HiresComponent1.hpp" -#include "HiresComponent3.hpp" +// #include "HiresBus.hpp" +// #include "HiresComponent1.hpp" +// #include "HiresComponent3.hpp" std::vector hires(const std::vector& y, const std::vector& yp); -template -int jac_hires(const std::vector& y, [[maybe_unused]] const std::vector& yp, GridKit::LinearAlgebra::DenseMatrix& jac, RealT alpha); +// template +// int jac_hires(const std::vector& y, [[maybe_unused]] const std::vector& yp, GridKit::LinearAlgebra::DenseMatrix& jac, RealT alpha); -template -void addCsrToDense( - GridKit::LinearAlgebra::CsrMatrix* csr, - GridKit::LinearAlgebra::DenseMatrix& dense, - GridKit::SubsystemModel* partition); +// template +// void addCsrToDense( +// GridKit::LinearAlgebra::CsrMatrix* csr, +// GridKit::LinearAlgebra::DenseMatrix& dense, +// GridKit::SubsystemModel* partition); int main(int /* argc */, char const** /* argv */) { - using Bus = GridKit::PowerElectronics::MicrogridBus; - Bus bus; - - GridKit::SubsystemModel* partition1 = new GridKit::SubsystemModel(); - GridKit::SubsystemModel* partition2 = new GridKit::SubsystemModel(); - - GridKit::HiresComponent1* comp1 = new GridKit::HiresComponent1(1); - GridKit::HiresBus* bus1 = new GridKit::HiresBus(2); - GridKit::HiresComponent3* comp3 = new GridKit::HiresComponent3(3); - - bus.allocate(); - - bus.setExternalConnectionNodes(0, 3); - bus.setExternalConnectionNodes(1, 4); - - comp1->allocate(); - comp3->allocate(); - bus1->allocate(); - - comp1->setExternalConnectionNodes(0, 3); - comp1->setExternalConnectionNodes(1, 4); - comp1->setExternalConnectionNodes(2, 0); - comp1->setExternalConnectionNodes(3, 1); - comp1->setExternalConnectionNodes(4, 2); - - bus1->setExternalConnectionNodes(0, 3); - bus1->setExternalConnectionNodes(1, 4); - - comp3->setExternalConnectionNodes(0, 3); - comp3->setExternalConnectionNodes(1, 4); - comp3->setExternalConnectionNodes(2, 5); - comp3->setExternalConnectionNodes(3, 6); - comp3->setExternalConnectionNodes(4, 7); - - GridKit::HiresComponent3 - comp3copy(*comp3); - GridKit::BusPartitionInterface* busInterface = new GridKit::BusPartitionInterface(bus, comp3copy, 4); - - busInterface->allocate(); - partition1->addComponent(comp1); - partition1->addComponent(bus1); - partition1->addComponent(busInterface); - partition1->addNode(&bus); - - partition2->addComponent(comp3); - - std::cout << "Msg" << std::endl; - partition1->allocate(); - partition2->allocate(); - - std::vector y = {1, 2, 3, 4, 5, 6, 7, 8}; - std::vector yp = {1, 2, 3, 4, 5, 6, 7, 8}; - - // Distribute externals to partition 1 - for (size_t i = 0; i < partition1->getExternSize(); i++) - { - partition1->getExternalDataY()[i] = y[partition1->getExternalIndices()[i]]; - partition1->getExternalDataYP()[i] = yp[partition1->getExternalIndices()[i]]; - } - - // Distribute externals to partition 2 - for (size_t i = 0; i < partition2->getExternSize(); i++) - { - partition2->getExternalDataY()[i] = y[partition2->getExternalIndices()[i]]; - partition2->getExternalDataYP()[i] = yp[partition2->getExternalIndices()[i]]; - } - - // Distribute internals to partition 1 - for (size_t i = 0; i < partition1->getInternalSize(); i++) - { - partition1->y()[i] = static_cast(1 + i); - partition1->yp()[i] = static_cast(1 + i); - } - - // Distribute internals to partition 2 - for (size_t i = 0; i < partition2->getInternalSize(); i++) - { - partition2->y()[i] = static_cast(6 + i); - partition2->yp()[i] = static_cast(6 + i); - } - - // Evaluate Residuals for each partition - partition1->evaluateResidual(); - partition2->evaluateResidual(); - - auto printTitle = [](std::string msg) -> void - { - std::cout << "\n------------- " << msg << " -----------" << std::endl; - printf("%-10s ---------- %10s\n", "Res Values", "Comp. Index"); - }; - - // Print Residuals from partition 1 - printTitle("Partition 1"); - for (size_t i = 0; i < partition1->getInternalSize(); i++) - { - auto com_index = partition1->getNodeConnection(static_cast(i)); - printf("%-10.5g ---------- %10zu\n", partition1->getResidual()[i], com_index); - } - - // Print Residuals from partition 2 - printTitle("Partition 2"); - for (size_t i = 0; i < partition2->getInternalSize(); i++) - { - auto com_index = partition2->getNodeConnection(static_cast(i)); - printf("%-10.5g ---------- %10zu\n", partition2->getResidual()[i], com_index); - } - - auto ref = hires(y, yp); - - printTitle("Reference Solution"); - for (size_t i = 0; i < 8; i++) - { - printf("%-10.5g ---------- %10zu\n", ref[i], i); - } - - partition1->updateTime(0, 1.0); - partition2->updateTime(0, 1.0); - - partition1->evaluateJacobian(); - partition2->evaluateJacobian(); - - GridKit::LinearAlgebra::DenseMatrix jac1(8, 8); - GridKit::LinearAlgebra::DenseMatrix jac2(8, 8); - - GridKit::LinearAlgebra::DenseMatrix jac_ref(8, 8); - - addCsrToDense(partition1->getCsrJacobian(), jac1, partition1); - addCsrToDense(partition2->getCsrJacobian(), jac2, partition2); - jac_hires(y, yp, jac_ref, 1.0); - - auto print_dense = [&](GridKit::LinearAlgebra::DenseMatrix& jc) -> void - { - for (size_t i = 0; i < 8; ++i) - { - for (size_t j = 0; j < 8; ++j) - { - std::cout << std::setw(10) << jc.getValue(i, j) << ' '; - } - std::cout << '\n'; - } - std::cout << '\n'; - }; - - print_dense(jac1); - print_dense(jac2); - print_dense(jac_ref); - - delete comp1; - delete bus1; - delete busInterface; - delete comp3; - delete partition1; - delete partition2; -} - -std::vector hires(const std::vector& y, const std::vector& yp) -{ - std::vector f(8); - - f[0] = -yp[0] - 1.71 * y[0] + 0.43 * y[1] + 8.32 * y[2] + 0.0007; - f[1] = -yp[1] + 1.71 * y[0] - 8.75 * y[1]; - f[2] = -yp[2] - 10.03 * y[2] + 0.43 * y[3] + 0.035 * y[4]; - f[3] = -yp[3] + 8.32 * y[1] + 1.71 * y[2] - 1.12 * y[3]; - f[4] = -yp[4] - 1.745 * y[4] + 0.43 * y[5] + 0.43 * y[6]; - f[5] = -yp[5] - 280 * y[5] * y[7] + 0.69 * y[3] + 1.71 * y[4] - 0.43 * y[5] + 0.69 * y[6]; - f[6] = -yp[6] + 280 * y[5] * y[7] - 1.81 * y[6]; - f[7] = -yp[7] - 280 * y[5] * y[7] + 1.81 * y[6]; - - return f; -} - -template -int jac_hires(const std::vector& y, [[maybe_unused]] const std::vector& yp, GridKit::LinearAlgebra::DenseMatrix& jac, RealT alpha) -{ - - jac.setValue(0, 0, -alpha - 1.71); - jac.setValue(0, 1, 0.43); - jac.setValue(0, 2, 8.32); - - jac.setValue(1, 0, 1.71); - jac.setValue(1, 1, -alpha - 8.75); - - jac.setValue(2, 2, -alpha - 10.03); - jac.setValue(2, 3, 0.43); - jac.setValue(2, 4, 0.035); - - jac.setValue(3, 1, 8.32); - jac.setValue(3, 2, 1.71); - jac.setValue(3, 3, -alpha - 1.12); - - jac.setValue(4, 4, -alpha - 1.745); - jac.setValue(4, 5, 0.43); - jac.setValue(4, 6, 0.43); - - jac.setValue(5, 3, 0.69); - jac.setValue(5, 4, 1.71); - jac.setValue(5, 5, -alpha - 280.0 * y[7] - 0.43); - jac.setValue(5, 6, 0.69); - jac.setValue(5, 7, -280.0 * y[5]); - - jac.setValue(6, 5, 280.0 * y[7]); - jac.setValue(6, 6, -alpha - 1.81); - jac.setValue(6, 7, 280.0 * y[5]); - - jac.setValue(7, 5, -280.0 * y[7]); - jac.setValue(7, 6, 1.81); - jac.setValue(7, 7, -alpha - 280.0 * y[5]); - + // using Bus = GridKit::PowerElectronics::MicrogridBus; + // Bus bus; + + // GridKit::SubsystemModel* partition1 = new GridKit::SubsystemModel(); + // GridKit::SubsystemModel* partition2 = new GridKit::SubsystemModel(); + + // GridKit::HiresComponent1* comp1 = new GridKit::HiresComponent1(1); + // GridKit::HiresBus* bus1 = new GridKit::HiresBus(2); + // GridKit::HiresComponent3* comp3 = new GridKit::HiresComponent3(3); + + // bus.allocate(); + + // bus.setExternalConnectionNodes(0, 3); + // bus.setExternalConnectionNodes(1, 4); + + // comp1->allocate(); + // comp3->allocate(); + // bus1->allocate(); + + // comp1->setExternalConnectionNodes(0, 3); + // comp1->setExternalConnectionNodes(1, 4); + // comp1->setExternalConnectionNodes(2, 0); + // comp1->setExternalConnectionNodes(3, 1); + // comp1->setExternalConnectionNodes(4, 2); + + // bus1->setExternalConnectionNodes(0, 3); + // bus1->setExternalConnectionNodes(1, 4); + + // comp3->setExternalConnectionNodes(0, 3); + // comp3->setExternalConnectionNodes(1, 4); + // comp3->setExternalConnectionNodes(2, 5); + // comp3->setExternalConnectionNodes(3, 6); + // comp3->setExternalConnectionNodes(4, 7); + + // GridKit::HiresComponent3 + // comp3copy(*comp3); + // GridKit::BusPartitionInterface* busInterface = new GridKit::BusPartitionInterface(bus, comp3copy, 4); + + // busInterface->allocate(); + // partition1->addComponent(comp1); + // partition1->addComponent(bus1); + // partition1->addComponent(busInterface); + // partition1->addNode(&bus); + + // partition2->addComponent(comp3); + + // std::cout << "Msg" << std::endl; + // partition1->allocate(); + // partition2->allocate(); + + // std::vector y = {1, 2, 3, 4, 5, 6, 7, 8}; + // std::vector yp = {1, 2, 3, 4, 5, 6, 7, 8}; + + // // Distribute externals to partition 1 + // for (size_t i = 0; i < partition1->getExternSize(); i++) + // { + // partition1->getExternalDataY()[i] = y[partition1->getExternalIndices()[i]]; + // partition1->getExternalDataYP()[i] = yp[partition1->getExternalIndices()[i]]; + // } + + // // Distribute externals to partition 2 + // for (size_t i = 0; i < partition2->getExternSize(); i++) + // { + // partition2->getExternalDataY()[i] = y[partition2->getExternalIndices()[i]]; + // partition2->getExternalDataYP()[i] = yp[partition2->getExternalIndices()[i]]; + // } + + // // Distribute internals to partition 1 + // for (size_t i = 0; i < partition1->getInternalSize(); i++) + // { + // partition1->y()[i] = static_cast(1 + i); + // partition1->yp()[i] = static_cast(1 + i); + // } + + // // Distribute internals to partition 2 + // for (size_t i = 0; i < partition2->getInternalSize(); i++) + // { + // partition2->y()[i] = static_cast(6 + i); + // partition2->yp()[i] = static_cast(6 + i); + // } + + // // Evaluate Residuals for each partition + // partition1->evaluateResidual(); + // partition2->evaluateResidual(); + + // auto printTitle = [](std::string msg) -> void + // { + // std::cout << "\n------------- " << msg << " -----------" << std::endl; + // printf("%-10s ---------- %10s\n", "Res Values", "Comp. Index"); + // }; + + // // Print Residuals from partition 1 + // printTitle("Partition 1"); + // for (size_t i = 0; i < partition1->getInternalSize(); i++) + // { + // auto com_index = partition1->getNodeConnection(static_cast(i)); + // printf("%-10.5g ---------- %10zu\n", partition1->getResidual()[i], com_index); + // } + + // // Print Residuals from partition 2 + // printTitle("Partition 2"); + // for (size_t i = 0; i < partition2->getInternalSize(); i++) + // { + // auto com_index = partition2->getNodeConnection(static_cast(i)); + // printf("%-10.5g ---------- %10zu\n", partition2->getResidual()[i], com_index); + // } + + // auto ref = hires(y, yp); + + // printTitle("Reference Solution"); + // for (size_t i = 0; i < 8; i++) + // { + // printf("%-10.5g ---------- %10zu\n", ref[i], i); + // } + + // partition1->updateTime(0, 1.0); + // partition2->updateTime(0, 1.0); + + // partition1->evaluateJacobian(); + // partition2->evaluateJacobian(); + + // GridKit::LinearAlgebra::DenseMatrix jac1(8, 8); + // GridKit::LinearAlgebra::DenseMatrix jac2(8, 8); + + // GridKit::LinearAlgebra::DenseMatrix jac_ref(8, 8); + + // addCsrToDense(partition1->getCsrJacobian(), jac1, partition1); + // addCsrToDense(partition2->getCsrJacobian(), jac2, partition2); + // jac_hires(y, yp, jac_ref, 1.0); + + // auto print_dense = [&](GridKit::LinearAlgebra::DenseMatrix& jc) -> void + // { + // for (size_t i = 0; i < 8; ++i) + // { + // for (size_t j = 0; j < 8; ++j) + // { + // std::cout << std::setw(10) << jc.getValue(i, j) << ' '; + // } + // std::cout << '\n'; + // } + // std::cout << '\n'; + // }; + + // print_dense(jac1); + // print_dense(jac2); + // print_dense(jac_ref); + + // delete comp1; + // delete bus1; + // delete busInterface; + // delete comp3; + // delete partition1; + // delete partition2; return 0; } -template -void addCsrToDense( - GridKit::LinearAlgebra::CsrMatrix* csr, - GridKit::LinearAlgebra::DenseMatrix& dense, - GridKit::SubsystemModel* partition) -{ - auto* row_ptr = csr->getRowData(GridKit::LinearAlgebra::memory::HOST); - auto* col_ind = csr->getColData(GridKit::LinearAlgebra::memory::HOST); - auto* values = csr->getValues(GridKit::LinearAlgebra::memory::HOST); - - assert(row_ptr != nullptr); - assert(col_ind != nullptr); - assert(values != nullptr); - - for (IdxT row = 0; row < csr->getNumRows(); ++row) - { - for (IdxT k = row_ptr[row]; k < row_ptr[row + 1]; ++k) - { - const IdxT col = col_ind[k]; - - auto r = partition->getNodeConnection(row); - auto c = partition->getNodeConnection(col); - - dense.setValue(r, c, dense.getValue(r, c) + values[k]); - } - } -} +// std::vector hires(const std::vector& y, const std::vector& yp) +// { +// std::vector f(8); + +// f[0] = -yp[0] - 1.71 * y[0] + 0.43 * y[1] + 8.32 * y[2] + 0.0007; +// f[1] = -yp[1] + 1.71 * y[0] - 8.75 * y[1]; +// f[2] = -yp[2] - 10.03 * y[2] + 0.43 * y[3] + 0.035 * y[4]; +// f[3] = -yp[3] + 8.32 * y[1] + 1.71 * y[2] - 1.12 * y[3]; +// f[4] = -yp[4] - 1.745 * y[4] + 0.43 * y[5] + 0.43 * y[6]; +// f[5] = -yp[5] - 280 * y[5] * y[7] + 0.69 * y[3] + 1.71 * y[4] - 0.43 * y[5] + 0.69 * y[6]; +// f[6] = -yp[6] + 280 * y[5] * y[7] - 1.81 * y[6]; +// f[7] = -yp[7] - 280 * y[5] * y[7] + 1.81 * y[6]; + +// return f; +// } + +// template +// int jac_hires(const std::vector& y, [[maybe_unused]] const std::vector& yp, GridKit::LinearAlgebra::DenseMatrix& jac, RealT alpha) +// { + +// jac.setValue(0, 0, -alpha - 1.71); +// jac.setValue(0, 1, 0.43); +// jac.setValue(0, 2, 8.32); + +// jac.setValue(1, 0, 1.71); +// jac.setValue(1, 1, -alpha - 8.75); + +// jac.setValue(2, 2, -alpha - 10.03); +// jac.setValue(2, 3, 0.43); +// jac.setValue(2, 4, 0.035); + +// jac.setValue(3, 1, 8.32); +// jac.setValue(3, 2, 1.71); +// jac.setValue(3, 3, -alpha - 1.12); + +// jac.setValue(4, 4, -alpha - 1.745); +// jac.setValue(4, 5, 0.43); +// jac.setValue(4, 6, 0.43); + +// jac.setValue(5, 3, 0.69); +// jac.setValue(5, 4, 1.71); +// jac.setValue(5, 5, -alpha - 280.0 * y[7] - 0.43); +// jac.setValue(5, 6, 0.69); +// jac.setValue(5, 7, -280.0 * y[5]); + +// jac.setValue(6, 5, 280.0 * y[7]); +// jac.setValue(6, 6, -alpha - 1.81); +// jac.setValue(6, 7, 280.0 * y[5]); + +// jac.setValue(7, 5, -280.0 * y[7]); +// jac.setValue(7, 6, 1.81); +// jac.setValue(7, 7, -alpha - 280.0 * y[5]); + +// return 0; +// } + +// template +// void addCsrToDense( +// GridKit::LinearAlgebra::CsrMatrix* csr, +// GridKit::LinearAlgebra::DenseMatrix& dense, +// GridKit::SubsystemModel* partition) +// { +// auto* row_ptr = csr->getRowData(GridKit::LinearAlgebra::memory::HOST); +// auto* col_ind = csr->getColData(GridKit::LinearAlgebra::memory::HOST); +// auto* values = csr->getValues(GridKit::LinearAlgebra::memory::HOST); + +// assert(row_ptr != nullptr); +// assert(col_ind != nullptr); +// assert(values != nullptr); + +// for (IdxT row = 0; row < csr->getNumRows(); ++row) +// { +// for (IdxT k = row_ptr[row]; k < row_ptr[row + 1]; ++k) +// { +// const IdxT col = col_ind[k]; + +// auto r = partition->getNodeConnection(row); +// auto c = partition->getNodeConnection(col); + +// dense.setValue(r, c, dense.getValue(r, c) + values[k]); +// } +// } +// } diff --git a/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp b/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp index 460b8ba67..6dd8563d7 100644 --- a/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp +++ b/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp @@ -27,13 +27,11 @@ int main() { /// @todo Needs to be modified. Some components are small relative to others thus /// there error is high (or could be matlab vector issue) - double abs_tol = 1.0e-8; - double rel_tol = 1.0e-8; - size_t max_step_number = 3000; - bool use_jac = true; + + bool use_jac = true; // Create model - auto* sysmodel = new GridKit::PowerElectronicsModel(rel_tol, abs_tol, use_jac, max_step_number); + auto* sysmodel = new GridKit::PowerElectronicsModel(use_jac); // Modeled after the problem in the paper double RN = 1.0e4; @@ -207,19 +205,25 @@ int main() yp.push_back(static_cast(i + 1)); } + auto* system_y = sysmodel->y().getData(); + auto* system_yp = sysmodel->yp().getData(); + for (size_t i = 0; i < sysmodel->size(); i++) { - sysmodel->y()[i] = y[i]; - sysmodel->yp()[i] = yp[i]; + system_y[i] = y[i]; + system_yp[i] = yp[i]; } + sysmodel->y().setDataUpdated(); + sysmodel->yp().setDataUpdated(); + sysmodel->updateTime(2, 5); sysmodel->evaluateResidual(); sysmodel->evaluateJacobian(); auto full_jac = sysmodel->getCsrJacobian(); - std::vector f_sysmodel = sysmodel->getResidual(); + auto* f_sysmodel = sysmodel->getResidual().getData(); std::vector*> partitions = {partition1, partition2}; @@ -236,12 +240,18 @@ int main() partition->getExternalDataYP()[i] = yp[partition->getExternalIndices()[i]]; } + auto* partition_y = partition->y().getData(); + auto* partition_yp = partition->yp().getData(); + for (size_t i = 0; i < partition->getInternalSize(); i++) { - partition->y()[i] = y[partition->getNodeConnection(i)]; - partition->yp()[i] = yp[partition->getNodeConnection(i)]; + partition_y[i] = y[partition->getNodeConnection(i)]; + partition_yp[i] = yp[partition->getNodeConnection(i)]; } + partition->y().setDataUpdated(); + partition->yp().setDataUpdated(); + partition->evaluateResidual(); partition->evaluateJacobian(); } @@ -266,30 +276,36 @@ int main() // Get internal residuals from partition 1 for (auto* partition : partitions) { + const auto* residual = partition->getResidual().getData(); + for (size_t i = 0; i < partition->getInternalSize(); i++) { - f[partition->getNodeConnection(i)] = partition->getResidual()[i]; + + f[partition->getNodeConnection(i)] = residual[i]; } + std::cout << std::endl; } double max_error = 0; for (size_t i = 0; i < sysmodel->size(); i++) { error[i] = (f_sysmodel[i] - f[i]) / f_sysmodel[i]; + + std::cout << i << " " << f[i] << " " << f_sysmodel[i] << " " << error[i] << std::endl; if (max_error < std::abs(error[i])) { max_error = std::abs(error[i]); } } + std::cout << "\nMax Error of Reference and Partition Evaluation: " << max_error << std::endl; + if (max_error > std::numeric_limits::epsilon()) { std::cout << "ERROR: Max Error too high!" << std::endl; return 1; } - std::cout << "\nMax Error of Reference and Partition Evaluation: " << max_error << std::endl; - delete sysmodel; delete partition1; delete partition2; diff --git a/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp b/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp index a27f0092a..2a6da84d0 100644 --- a/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp +++ b/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp @@ -119,15 +119,8 @@ RunResult printMicrogridSystems(index_type N_size, index_type num_partitions) bool use_jac = true; - real_type rel_tol = 1e-5; - real_type abs_tol = 1e-5; - index_type max_steps = 2000; - // Create circuit model - auto* sys_model_control = new PowerElectronicsModel(rel_tol, - abs_tol, - use_jac, - max_steps); + auto* sys_model_control = new PowerElectronicsModel(use_jac); // Ensure minimum size requirement assert(N_size >= 1); @@ -176,9 +169,13 @@ RunResult printMicrogridSystems(index_type N_size, index_type num_partitions) // 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 @@ -326,12 +323,18 @@ RunResult printMicrogridSystems(index_type N_size, index_type num_partitions) auto start_time = std::chrono::high_resolution_clock::now(); + auto* sys_model_y = sys_model_control->y().getData(); + auto* sys_model_yp = sys_model_control->yp().getData(); + for (size_t i = 0; i < sys_model_control->size(); i++) { - sys_model_control->y()[i] = y[i]; - sys_model_control->yp()[i] = yp[i]; + sys_model_y[i] = y[i]; + sys_model_yp[i] = yp[i]; } + sys_model_control->y().setDataUpdated(); + sys_model_control->yp().setDataUpdated(); + sys_model_control->updateTime(2, 5); sys_model_control->evaluateResidual(); @@ -340,7 +343,7 @@ RunResult printMicrogridSystems(index_type N_size, index_type num_partitions) sys_model_control->evaluateJacobian(); - auto& f_sysmodel_control = sys_model_control->getResidual(); + auto* f_sysmodel_control = sys_model_control->getResidual().getData(); auto* full_jac = sys_model_control->getCsrJacobian(); //--------------------------------------------------------------- @@ -437,20 +440,27 @@ RunResult printMicrogridSystems(index_type N_size, index_type num_partitions) partition->getExternalDataYP()[i] = yp[partition->getExternalIndices()[i]]; } + auto* partition_y = partition->y().getData(); + auto* partition_yp = partition->yp().getData(); + // Distribute internal variables for (size_t i = 0; i < partition->getInternalSize(); i++) { - partition->y()[i] = y[partition->getNodeConnection(i)]; - partition->yp()[i] = yp[partition->getNodeConnection(i)]; + partition_y[i] = y[partition->getNodeConnection(i)]; + partition_yp[i] = yp[partition->getNodeConnection(i)]; } + partition->y().setDataUpdated(); + partition->yp().setDataUpdated(); + // Evaluate residual of this partition partition->evaluateResidual(); + auto* residual = partition->getResidual().getData(); // Reconstructs the monolithic residual from the partition residuals for (size_t i = 0; i < partition->getInternalSize(); i++) { - f[partition->getNodeConnection(i)] = partition->getResidual()[i]; + f[partition->getNodeConnection(i)] = residual[i]; } } @@ -509,11 +519,17 @@ RunResult printMicrogridSystems(index_type N_size, index_type num_partitions) } for (auto* linescpy : linesCopies) + { delete linescpy; + } for (auto* partition : subsystems) + { delete partition; + } for (auto* part_interface : partitionInterface) + { delete part_interface; + } delete sys_model_control; return result; diff --git a/examples/PowerElectronics/Partition/jac_test_helper.hpp b/examples/PowerElectronics/Partition/jac_test_helper.hpp index 10daf9631..8851bc2a3 100644 --- a/examples/PowerElectronics/Partition/jac_test_helper.hpp +++ b/examples/PowerElectronics/Partition/jac_test_helper.hpp @@ -6,6 +6,7 @@ #include #include +#include #include namespace GridKit @@ -20,12 +21,11 @@ namespace GridKit GridKit::SubsystemModel& subsystem, RealT tolerance = static_cast(1e-12)) { - constexpr auto host = GridKit::LinearAlgebra::memory::HOST; - + constexpr auto host = memory::HOST; // Full-system CSR data. - const IdxT* full_rows = full_jac.getRowData(host); - const IdxT* full_cols = full_jac.getColData(host); - const RealT* full_vals = full_jac.getValues(host); + const IdxT* full_rows = full_jac.getRowData(host); + const IdxT* full_cols = full_jac.getColData(host); + const RealT* full_vals = full_jac.getValues(host); // Subsystem CSR data. const IdxT* sub_rows = sub_jac.getRowData(host); From 533806f91f1c4bd50ef1b53c987fe1c5110a25df Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Mon, 20 Jul 2026 05:06:22 +0000 Subject: [PATCH 24/34] Updated copy constructor in circuit component --- GridKit/Model/PowerElectronics/CircuitComponent.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/GridKit/Model/PowerElectronics/CircuitComponent.hpp b/GridKit/Model/PowerElectronics/CircuitComponent.hpp index a7c462d76..c7143d446 100644 --- a/GridKit/Model/PowerElectronics/CircuitComponent.hpp +++ b/GridKit/Model/PowerElectronics/CircuitComponent.hpp @@ -64,9 +64,7 @@ namespace GridKit } destination.resize(source_size); - - const int error_code = destination.copyFromExternal(source); - assert(error_code == 0); + destination.copyFromExternal(source); }; /* From 9ebecc9ee8fb688e1eac795c3434c47985f571e9 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Mon, 20 Jul 2026 05:07:06 +0000 Subject: [PATCH 25/34] Removed Neumaier Compensation --- .../Model/PowerElectronics/SubsystemModel.hpp | 42 ------------------- 1 file changed, 42 deletions(-) diff --git a/GridKit/Model/PowerElectronics/SubsystemModel.hpp b/GridKit/Model/PowerElectronics/SubsystemModel.hpp index cf793725e..51df8a508 100644 --- a/GridKit/Model/PowerElectronics/SubsystemModel.hpp +++ b/GridKit/Model/PowerElectronics/SubsystemModel.hpp @@ -331,11 +331,6 @@ namespace GridKit for (IdxT i = 0; i < this->getInternalSize(); i++) { f[i] = 0.0; - - // if (use_neumaier_sum) - // { - // neumaier_compensation[i] = 0.0; - // } } this->distributeVectors(); @@ -363,23 +358,11 @@ namespace GridKit //@todo should do a different grounding check if (component->getNodeConnection(j) != neg1_ && component->getNodeConnection(j) < this->getInternalSize()) { - // if (!use_neumaier_sum) - // { f[component->getNodeConnection(j)] += residual[j]; - // } - // else - // { - // getNeumaierCompensation(f_[component->getNodeConnection(j)], residual[j], component->getNodeConnection(j)); - // } } } } - // if (use_neumaier_sum) - // { - // addNeumaierCompensation(f_); - // } - f_.setDataUpdated(); return 0; @@ -659,28 +642,6 @@ namespace GridKit forcing_function_ = std::move(function); } - // void getNeumaierCompensation(ScalarT& sum, const ScalarT& x, const IdxT& index) - // { - // ScalarT t = sum + x; - // if (std::abs(sum) >= std::abs(x)) - // { - // neumaier_compensation[index] += (sum - t) + x; - // } - // else - // { - // neumaier_compensation[index] += (x - t) + sum; - // } - // sum = t; - // } - - // void addNeumaierCompensation(VectorT f) - // { - // for (IdxT i = 0; i < size_; i++) - // { - // f[i] += neumaier_compensation[i]; - // } - // } - std::unordered_map& getInternalMap() { return internal_map_; @@ -700,9 +661,6 @@ namespace GridKit std::unordered_map external_map_; std::vector external_indices_; - bool use_neumaier_sum{false}; - - std::vector neumaier_compensation; std::vector y_ext_; std::vector yp_ext_; std::vector f_ext_; From f8b56bea630b6c493e5678be2b624496298c7454 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Mon, 20 Jul 2026 05:07:45 +0000 Subject: [PATCH 26/34] Updated Hires test problem --- .../PowerElectronics/Partition/HiresBus.hpp | 44 ++- .../Partition/HiresComponent1.hpp | 44 ++- .../Partition/HiresComponent3.hpp | 47 ++- .../PowerElectronics/Partition/Partition.cpp | 360 ++++++++---------- 4 files changed, 265 insertions(+), 230 deletions(-) diff --git a/examples/PowerElectronics/Partition/HiresBus.hpp b/examples/PowerElectronics/Partition/HiresBus.hpp index ae834aaba..273570e30 100644 --- a/examples/PowerElectronics/Partition/HiresBus.hpp +++ b/examples/PowerElectronics/Partition/HiresBus.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include namespace GridKit { @@ -11,8 +12,9 @@ namespace GridKit template class HiresBus : public CircuitComponent { - using RealT = typename CircuitComponent::RealT; - using MatrixT = typename CircuitComponent::MatrixT; + + using RealT = typename CircuitComponent::RealT; + using NodeT = typename PowerElectronics::NodeBase; using CircuitComponent::size_; using CircuitComponent::nnz_; @@ -23,6 +25,7 @@ namespace GridKit using CircuitComponent::yp_; using CircuitComponent::yp_int_; using CircuitComponent::tag_; + using CircuitComponent::abs_tol_; using CircuitComponent::f_; using CircuitComponent::f_int_; using CircuitComponent::g_; @@ -38,7 +41,7 @@ namespace GridKit using CircuitComponent::n_intern_; public: - HiresBus(IdxT id) + HiresBus(NodeT* bus, IdxT id) : node_ref_(bus) { size_ = 2; n_intern_ = 0; @@ -56,6 +59,9 @@ namespace GridKit { CircuitComponent::allocate(); + this->setExternalConnectionNodes(0, node_ref_->getNodeConnection(0)); + this->setExternalConnectionNodes(1, node_ref_->getNodeConnection(1)); + return 0; } @@ -76,8 +82,15 @@ namespace GridKit int evaluateExternalResidual() { - f_[0] = -yp_[0] - y_[0]; - f_[1] = -yp_[1] - y_[1]; + auto* y = y_.getData(); + auto* yp = yp_.getData(); + auto* f = f_.getData(); + + f[0] = -yp[0] - y[0]; + f[1] = -yp[1] - y[1]; + + f_.setDataUpdated(); + return 0; } @@ -113,5 +126,26 @@ 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. + */ + int setAbsoluteTolerance(RealT rel_tol) + { + abs_tol_.setToConst(static_cast(rel_tol)); + return 0; + } + + private: + NodeT* node_ref_; }; } // namespace GridKit diff --git a/examples/PowerElectronics/Partition/HiresComponent1.hpp b/examples/PowerElectronics/Partition/HiresComponent1.hpp index d72a7a068..d8931739f 100644 --- a/examples/PowerElectronics/Partition/HiresComponent1.hpp +++ b/examples/PowerElectronics/Partition/HiresComponent1.hpp @@ -3,6 +3,7 @@ #pragma once #include +#include namespace GridKit { @@ -13,8 +14,8 @@ namespace GridKit template class HiresComponent1 : public CircuitComponent { - using RealT = typename CircuitComponent::RealT; - using MatrixT = typename CircuitComponent::MatrixT; + using RealT = typename CircuitComponent::RealT; + using NodeT = typename PowerElectronics::NodeBase; using CircuitComponent::size_; using CircuitComponent::nnz_; @@ -25,6 +26,7 @@ namespace GridKit using CircuitComponent::yp_; using CircuitComponent::yp_int_; using CircuitComponent::tag_; + using CircuitComponent::abs_tol_; using CircuitComponent::f_; using CircuitComponent::f_int_; using CircuitComponent::g_; @@ -40,7 +42,7 @@ namespace GridKit using CircuitComponent::n_intern_; public: - HiresComponent1(IdxT id) + HiresComponent1(NodeT* bus, IdxT id) : node_ref_(bus) { size_ = 5; n_intern_ = 3; @@ -58,6 +60,9 @@ namespace GridKit { CircuitComponent::allocate(); + this->setExternalConnectionNodes(0, node_ref_->getNodeConnection(0)); + this->setExternalConnectionNodes(1, node_ref_->getNodeConnection(1)); + return 0; } @@ -73,20 +78,26 @@ namespace GridKit int evaluateInternalResidual() { + auto* y = y_.getData(); // Internals f_int_[0] = -yp_int_[0] - 1.71 * y_int_[0] + 0.43 * y_int_[1] + 8.32 * y_int_[2] + 0.0007; f_int_[1] = -yp_int_[1] + 1.71 * y_int_[0] - 8.75 * y_int_[1]; - f_int_[2] = -yp_int_[2] - 10.03 * y_int_[2] + 0.43 * y_[0] + 0.035 * y_[1]; + f_int_[2] = -yp_int_[2] - 10.03 * y_int_[2] + 0.43 * y[0] + 0.035 * y[1]; return 0; } int evaluateExternalResidual() { + auto* y = y_.getData(); + auto* f = f_.getData(); + // outputs - f_[0] = 8.32 * y_int_[1] + 1.71 * y_int_[2] - 0.1 * y_[0]; - f_[1] = -0.7 * y_[1]; + f[0] = 8.32 * y_int_[1] + 1.71 * y_int_[2] - 0.1 * y[0]; + f[1] = -0.7 * y[1]; + + f_.setDataUpdated(); return 0; } @@ -132,5 +143,26 @@ 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. + */ + int setAbsoluteTolerance(RealT rel_tol) + { + abs_tol_.setToConst(static_cast(rel_tol)); + return 0; + } + + private: + NodeT* node_ref_; }; } // namespace GridKit diff --git a/examples/PowerElectronics/Partition/HiresComponent3.hpp b/examples/PowerElectronics/Partition/HiresComponent3.hpp index 81314895d..92380bb8a 100644 --- a/examples/PowerElectronics/Partition/HiresComponent3.hpp +++ b/examples/PowerElectronics/Partition/HiresComponent3.hpp @@ -1,8 +1,7 @@ - - #pragma once #include +#include namespace GridKit { @@ -13,8 +12,8 @@ namespace GridKit template class HiresComponent3 : public CircuitComponent { - using RealT = typename CircuitComponent::RealT; - using MatrixT = typename CircuitComponent::MatrixT; + using RealT = typename CircuitComponent::RealT; + using NodeT = typename PowerElectronics::NodeBase; using CircuitComponent::size_; using CircuitComponent::nnz_; @@ -25,6 +24,7 @@ namespace GridKit using CircuitComponent::yp_; using CircuitComponent::yp_int_; using CircuitComponent::tag_; + using CircuitComponent::abs_tol_; using CircuitComponent::f_; using CircuitComponent::f_int_; using CircuitComponent::g_; @@ -40,7 +40,7 @@ namespace GridKit using CircuitComponent::n_intern_; public: - HiresComponent3(IdxT id) + HiresComponent3(NodeT* bus, IdxT id) : node_ref_(bus) { size_ = 5; n_intern_ = 3; @@ -58,6 +58,9 @@ namespace GridKit { CircuitComponent::allocate(); + this->setExternalConnectionNodes(0, node_ref_->getNodeConnection(0)); + this->setExternalConnectionNodes(1, node_ref_->getNodeConnection(1)); + return 0; } @@ -73,8 +76,10 @@ namespace GridKit int evaluateInternalResidual() { + auto* y = y_.getData(); + // Internals - f_int_[0] = -yp_int_[0] - 280 * y_int_[0] * y_int_[2] + 0.69 * y_[0] + 1.71 * y_[1] - 0.43 * y_int_[0] + 0.69 * y_int_[1]; + f_int_[0] = -yp_int_[0] - 280 * y_int_[0] * y_int_[2] + 0.69 * y[0] + 1.71 * y[1] - 0.43 * y_int_[0] + 0.69 * y_int_[1]; f_int_[1] = -yp_int_[1] + 280 * y_int_[0] * y_int_[2] - 1.81 * y_int_[1]; f_int_[2] = -yp_int_[2] - 280 * y_int_[0] * y_int_[2] + 1.81 * y_int_[1]; @@ -83,9 +88,14 @@ namespace GridKit int evaluateExternalResidual() { + auto* y = y_.getData(); + auto* f = f_.getData(); + // Externals - f_[0] = -0.02 * y_[0]; - f_[1] = -0.045 * y_[1] + 0.43 * y_int_[0] + 0.43 * y_int_[1]; + f[0] = -0.02 * y[0]; + f[1] = -0.045 * y[1] + 0.43 * y_int_[0] + 0.43 * y_int_[1]; + + f_.setDataUpdated(); return 0; } @@ -144,5 +154,26 @@ 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. + */ + int setAbsoluteTolerance(RealT rel_tol) + { + abs_tol_.setToConst(static_cast(rel_tol)); + return 0; + } + + private: + NodeT* node_ref_; }; } // namespace GridKit diff --git a/examples/PowerElectronics/Partition/Partition.cpp b/examples/PowerElectronics/Partition/Partition.cpp index ab6d981f5..93f14cbc8 100644 --- a/examples/PowerElectronics/Partition/Partition.cpp +++ b/examples/PowerElectronics/Partition/Partition.cpp @@ -3,203 +3,169 @@ #define _USE_MATH_DEFINES #include #include -// #include -// #include -// #include +#include +#include +#include #include #include #include -// #include "HiresBus.hpp" -// #include "HiresComponent1.hpp" -// #include "HiresComponent3.hpp" +#include "HiresBus.hpp" +#include "HiresComponent1.hpp" +#include "HiresComponent3.hpp" std::vector hires(const std::vector& y, const std::vector& yp); -// template -// int jac_hires(const std::vector& y, [[maybe_unused]] const std::vector& yp, GridKit::LinearAlgebra::DenseMatrix& jac, RealT alpha); - -// template -// void addCsrToDense( -// GridKit::LinearAlgebra::CsrMatrix* csr, -// GridKit::LinearAlgebra::DenseMatrix& dense, -// GridKit::SubsystemModel* partition); - int main(int /* argc */, char const** /* argv */) { - // using Bus = GridKit::PowerElectronics::MicrogridBus; - // Bus bus; - - // GridKit::SubsystemModel* partition1 = new GridKit::SubsystemModel(); - // GridKit::SubsystemModel* partition2 = new GridKit::SubsystemModel(); - - // GridKit::HiresComponent1* comp1 = new GridKit::HiresComponent1(1); - // GridKit::HiresBus* bus1 = new GridKit::HiresBus(2); - // GridKit::HiresComponent3* comp3 = new GridKit::HiresComponent3(3); - - // bus.allocate(); - - // bus.setExternalConnectionNodes(0, 3); - // bus.setExternalConnectionNodes(1, 4); - - // comp1->allocate(); - // comp3->allocate(); - // bus1->allocate(); - - // comp1->setExternalConnectionNodes(0, 3); - // comp1->setExternalConnectionNodes(1, 4); - // comp1->setExternalConnectionNodes(2, 0); - // comp1->setExternalConnectionNodes(3, 1); - // comp1->setExternalConnectionNodes(4, 2); - - // bus1->setExternalConnectionNodes(0, 3); - // bus1->setExternalConnectionNodes(1, 4); - - // comp3->setExternalConnectionNodes(0, 3); - // comp3->setExternalConnectionNodes(1, 4); - // comp3->setExternalConnectionNodes(2, 5); - // comp3->setExternalConnectionNodes(3, 6); - // comp3->setExternalConnectionNodes(4, 7); - - // GridKit::HiresComponent3 - // comp3copy(*comp3); - // GridKit::BusPartitionInterface* busInterface = new GridKit::BusPartitionInterface(bus, comp3copy, 4); - - // busInterface->allocate(); - // partition1->addComponent(comp1); - // partition1->addComponent(bus1); - // partition1->addComponent(busInterface); - // partition1->addNode(&bus); - - // partition2->addComponent(comp3); - - // std::cout << "Msg" << std::endl; - // partition1->allocate(); - // partition2->allocate(); - - // std::vector y = {1, 2, 3, 4, 5, 6, 7, 8}; - // std::vector yp = {1, 2, 3, 4, 5, 6, 7, 8}; - - // // Distribute externals to partition 1 - // for (size_t i = 0; i < partition1->getExternSize(); i++) - // { - // partition1->getExternalDataY()[i] = y[partition1->getExternalIndices()[i]]; - // partition1->getExternalDataYP()[i] = yp[partition1->getExternalIndices()[i]]; - // } - - // // Distribute externals to partition 2 - // for (size_t i = 0; i < partition2->getExternSize(); i++) - // { - // partition2->getExternalDataY()[i] = y[partition2->getExternalIndices()[i]]; - // partition2->getExternalDataYP()[i] = yp[partition2->getExternalIndices()[i]]; - // } - - // // Distribute internals to partition 1 - // for (size_t i = 0; i < partition1->getInternalSize(); i++) - // { - // partition1->y()[i] = static_cast(1 + i); - // partition1->yp()[i] = static_cast(1 + i); - // } - - // // Distribute internals to partition 2 - // for (size_t i = 0; i < partition2->getInternalSize(); i++) - // { - // partition2->y()[i] = static_cast(6 + i); - // partition2->yp()[i] = static_cast(6 + i); - // } - - // // Evaluate Residuals for each partition - // partition1->evaluateResidual(); - // partition2->evaluateResidual(); - - // auto printTitle = [](std::string msg) -> void - // { - // std::cout << "\n------------- " << msg << " -----------" << std::endl; - // printf("%-10s ---------- %10s\n", "Res Values", "Comp. Index"); - // }; - - // // Print Residuals from partition 1 - // printTitle("Partition 1"); - // for (size_t i = 0; i < partition1->getInternalSize(); i++) - // { - // auto com_index = partition1->getNodeConnection(static_cast(i)); - // printf("%-10.5g ---------- %10zu\n", partition1->getResidual()[i], com_index); - // } - - // // Print Residuals from partition 2 - // printTitle("Partition 2"); - // for (size_t i = 0; i < partition2->getInternalSize(); i++) - // { - // auto com_index = partition2->getNodeConnection(static_cast(i)); - // printf("%-10.5g ---------- %10zu\n", partition2->getResidual()[i], com_index); - // } - - // auto ref = hires(y, yp); - - // printTitle("Reference Solution"); - // for (size_t i = 0; i < 8; i++) - // { - // printf("%-10.5g ---------- %10zu\n", ref[i], i); - // } - - // partition1->updateTime(0, 1.0); - // partition2->updateTime(0, 1.0); - - // partition1->evaluateJacobian(); - // partition2->evaluateJacobian(); - - // GridKit::LinearAlgebra::DenseMatrix jac1(8, 8); - // GridKit::LinearAlgebra::DenseMatrix jac2(8, 8); - - // GridKit::LinearAlgebra::DenseMatrix jac_ref(8, 8); - - // addCsrToDense(partition1->getCsrJacobian(), jac1, partition1); - // addCsrToDense(partition2->getCsrJacobian(), jac2, partition2); - // jac_hires(y, yp, jac_ref, 1.0); - - // auto print_dense = [&](GridKit::LinearAlgebra::DenseMatrix& jc) -> void - // { - // for (size_t i = 0; i < 8; ++i) - // { - // for (size_t j = 0; j < 8; ++j) - // { - // std::cout << std::setw(10) << jc.getValue(i, j) << ' '; - // } - // std::cout << '\n'; - // } - // std::cout << '\n'; - // }; - - // print_dense(jac1); - // print_dense(jac2); - // print_dense(jac_ref); - - // delete comp1; - // delete bus1; - // delete busInterface; - // delete comp3; - // delete partition1; - // delete partition2; + using Bus = GridKit::PowerElectronics::MicrogridBus; + Bus bus; + + GridKit::SubsystemModel* partition1 = new GridKit::SubsystemModel(); + GridKit::SubsystemModel* partition2 = new GridKit::SubsystemModel(); + + GridKit::HiresComponent1* comp1 = new GridKit::HiresComponent1(&bus, 1); + GridKit::HiresBus* bus1 = new GridKit::HiresBus(&bus, 2); + GridKit::HiresComponent3* comp3 = new GridKit::HiresComponent3(&bus, 3); + + bus.allocate(); + + bus.setExternalConnectionNodes(0, 3); + bus.setExternalConnectionNodes(1, 4); + + comp1->allocate(); + comp3->allocate(); + bus1->allocate(); + + comp1->setExternalConnectionNodes(2, 0); + comp1->setExternalConnectionNodes(3, 1); + comp1->setExternalConnectionNodes(4, 2); + + bus1->setExternalConnectionNodes(0, 3); + bus1->setExternalConnectionNodes(1, 4); + + comp3->setExternalConnectionNodes(2, 5); + comp3->setExternalConnectionNodes(3, 6); + comp3->setExternalConnectionNodes(4, 7); + + GridKit::HiresComponent3 comp3copy(*comp3); + GridKit::BusPartitionInterface* busInterface = new GridKit::BusPartitionInterface(bus, comp3copy, 4); + + busInterface->allocate(); + partition1->addComponent(comp1); + partition1->addComponent(bus1); + partition1->addComponent(busInterface); + partition1->addNode(&bus); + + partition2->addComponent(comp3); + + auto subsystems = {partition1, partition2}; + + std::vector y = {1, 2, 3, 4, 5, 6, 7, 8}; + std::vector yp = {1, 2, 3, 4, 5, 6, 7, 8}; + + // Distribute externals to partition 1 + + for (auto* partition : subsystems) + { + partition->allocate(); + partition->updateTime(2, 5); + + for (size_t i = 0; i < partition->getExternSize(); i++) + { + partition->getExternalDataY()[i] = y[partition->getExternalIndices()[i]]; + partition->getExternalDataYP()[i] = yp[partition->getExternalIndices()[i]]; + } + + auto* partition_y = partition->y().getData(); + auto* partition_yp = partition->yp().getData(); + + for (size_t i = 0; i < partition->getInternalSize(); i++) + { + partition_y[i] = y[partition->getNodeConnection(i)]; + partition_yp[i] = yp[partition->getNodeConnection(i)]; + } + + partition->y().setDataUpdated(); + partition->yp().setDataUpdated(); + + partition->evaluateResidual(); + partition->evaluateJacobian(); + } + + auto printHeader = [](const std::string& title) + { + std::cout << "\n------------- " << title << " -----------\n"; + + std::cout << std::left << std::setw(10) << "Res Values" + << " ---------- " + << std::right << std::setw(10) << "Comp. Index" + << '\n'; + }; + + auto printRow = [](double residual, size_t index) + { + std::cout << std::left << std::setw(10) + << std::defaultfloat << std::setprecision(5) + << residual + << " ---------- " + << std::right << std::setw(10) + << index + << '\n'; + }; + + auto printPartitionResiduals = [&](auto* partition, const std::string& title) + { + printHeader(title); + + auto* residual = partition->getResidual().getData(); + + for (size_t i = 0; i < partition->getInternalSize(); ++i) + { + const auto comp_index = partition->getNodeConnection(i); + printRow(residual[i], comp_index); + } + }; + + printPartitionResiduals(partition1, "Partition 1"); + printPartitionResiduals(partition2, "Partition 2"); + + auto ref = hires(y, yp); + + printHeader("Reference Output"); + for (size_t i = 0; i < ref.size(); ++i) + { + printRow(ref[i], i); + } + + delete comp1; + delete bus1; + delete busInterface; + delete comp3; + + delete partition1; + delete partition2; + return 0; } -// std::vector hires(const std::vector& y, const std::vector& yp) -// { -// std::vector f(8); - -// f[0] = -yp[0] - 1.71 * y[0] + 0.43 * y[1] + 8.32 * y[2] + 0.0007; -// f[1] = -yp[1] + 1.71 * y[0] - 8.75 * y[1]; -// f[2] = -yp[2] - 10.03 * y[2] + 0.43 * y[3] + 0.035 * y[4]; -// f[3] = -yp[3] + 8.32 * y[1] + 1.71 * y[2] - 1.12 * y[3]; -// f[4] = -yp[4] - 1.745 * y[4] + 0.43 * y[5] + 0.43 * y[6]; -// f[5] = -yp[5] - 280 * y[5] * y[7] + 0.69 * y[3] + 1.71 * y[4] - 0.43 * y[5] + 0.69 * y[6]; -// f[6] = -yp[6] + 280 * y[5] * y[7] - 1.81 * y[6]; -// f[7] = -yp[7] - 280 * y[5] * y[7] + 1.81 * y[6]; - -// return f; -// } +std::vector hires(const std::vector& y, const std::vector& yp) +{ + std::vector f(8); + + f[0] = -yp[0] - 1.71 * y[0] + 0.43 * y[1] + 8.32 * y[2] + 0.0007; + f[1] = -yp[1] + 1.71 * y[0] - 8.75 * y[1]; + f[2] = -yp[2] - 10.03 * y[2] + 0.43 * y[3] + 0.035 * y[4]; + f[3] = -yp[3] + 8.32 * y[1] + 1.71 * y[2] - 1.12 * y[3]; + f[4] = -yp[4] - 1.745 * y[4] + 0.43 * y[5] + 0.43 * y[6]; + f[5] = -yp[5] - 280 * y[5] * y[7] + 0.69 * y[3] + 1.71 * y[4] - 0.43 * y[5] + 0.69 * y[6]; + f[6] = -yp[6] + 280 * y[5] * y[7] - 1.81 * y[6]; + f[7] = -yp[7] - 280 * y[5] * y[7] + 1.81 * y[6]; + + return f; +} // template // int jac_hires(const std::vector& y, [[maybe_unused]] const std::vector& yp, GridKit::LinearAlgebra::DenseMatrix& jac, RealT alpha) @@ -240,31 +206,3 @@ int main(int /* argc */, char const** /* argv */) // return 0; // } - -// template -// void addCsrToDense( -// GridKit::LinearAlgebra::CsrMatrix* csr, -// GridKit::LinearAlgebra::DenseMatrix& dense, -// GridKit::SubsystemModel* partition) -// { -// auto* row_ptr = csr->getRowData(GridKit::LinearAlgebra::memory::HOST); -// auto* col_ind = csr->getColData(GridKit::LinearAlgebra::memory::HOST); -// auto* values = csr->getValues(GridKit::LinearAlgebra::memory::HOST); - -// assert(row_ptr != nullptr); -// assert(col_ind != nullptr); -// assert(values != nullptr); - -// for (IdxT row = 0; row < csr->getNumRows(); ++row) -// { -// for (IdxT k = row_ptr[row]; k < row_ptr[row + 1]; ++k) -// { -// const IdxT col = col_ind[k]; - -// auto r = partition->getNodeConnection(row); -// auto c = partition->getNodeConnection(col); - -// dense.setValue(r, c, dense.getValue(r, c) + values[k]); -// } -// } -// } From 85d29f9845b9818095ff3d5b9965ae2ac5e13c88 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Mon, 20 Jul 2026 05:08:41 +0000 Subject: [PATCH 27/34] Removed print statements --- examples/PowerElectronics/Partition/PartitionMicrogrid.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp b/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp index 6dd8563d7..d72c50f4e 100644 --- a/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp +++ b/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp @@ -283,7 +283,6 @@ int main() f[partition->getNodeConnection(i)] = residual[i]; } - std::cout << std::endl; } double max_error = 0; @@ -291,7 +290,6 @@ int main() { error[i] = (f_sysmodel[i] - f[i]) / f_sysmodel[i]; - std::cout << i << " " << f[i] << " " << f_sysmodel[i] << " " << error[i] << std::endl; if (max_error < std::abs(error[i])) { max_error = std::abs(error[i]); From 81819c00cb07d965635026e91d4bfe47e499b33c Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Mon, 20 Jul 2026 05:09:28 +0000 Subject: [PATCH 28/34] Apply pre-commit fixes --- examples/PowerElectronics/Partition/HiresBus.hpp | 3 ++- examples/PowerElectronics/Partition/HiresComponent1.hpp | 3 ++- examples/PowerElectronics/Partition/HiresComponent3.hpp | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/PowerElectronics/Partition/HiresBus.hpp b/examples/PowerElectronics/Partition/HiresBus.hpp index 273570e30..d37e396d3 100644 --- a/examples/PowerElectronics/Partition/HiresBus.hpp +++ b/examples/PowerElectronics/Partition/HiresBus.hpp @@ -41,7 +41,8 @@ namespace GridKit using CircuitComponent::n_intern_; public: - HiresBus(NodeT* bus, IdxT id) : node_ref_(bus) + HiresBus(NodeT* bus, IdxT id) + : node_ref_(bus) { size_ = 2; n_intern_ = 0; diff --git a/examples/PowerElectronics/Partition/HiresComponent1.hpp b/examples/PowerElectronics/Partition/HiresComponent1.hpp index d8931739f..503bf963d 100644 --- a/examples/PowerElectronics/Partition/HiresComponent1.hpp +++ b/examples/PowerElectronics/Partition/HiresComponent1.hpp @@ -42,7 +42,8 @@ namespace GridKit using CircuitComponent::n_intern_; public: - HiresComponent1(NodeT* bus, IdxT id) : node_ref_(bus) + HiresComponent1(NodeT* bus, IdxT id) + : node_ref_(bus) { size_ = 5; n_intern_ = 3; diff --git a/examples/PowerElectronics/Partition/HiresComponent3.hpp b/examples/PowerElectronics/Partition/HiresComponent3.hpp index 92380bb8a..5e8ddf4cd 100644 --- a/examples/PowerElectronics/Partition/HiresComponent3.hpp +++ b/examples/PowerElectronics/Partition/HiresComponent3.hpp @@ -40,7 +40,8 @@ namespace GridKit using CircuitComponent::n_intern_; public: - HiresComponent3(NodeT* bus, IdxT id) : node_ref_(bus) + HiresComponent3(NodeT* bus, IdxT id) + : node_ref_(bus) { size_ = 5; n_intern_ = 3; From 1344722878961cd2bfad3c3e1fe183d758738da4 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Thu, 23 Jul 2026 05:14:19 +0000 Subject: [PATCH 29/34] Make SubsystemModel inherit from PowerElectronicsModel for code reuse --- .../Model/PowerElectronics/SubsystemModel.hpp | 306 +++--------------- .../SystemModelPowerElectronics.hpp | 41 ++- 2 files changed, 56 insertions(+), 291 deletions(-) diff --git a/GridKit/Model/PowerElectronics/SubsystemModel.hpp b/GridKit/Model/PowerElectronics/SubsystemModel.hpp index 51df8a508..35bb0eab9 100644 --- a/GridKit/Model/PowerElectronics/SubsystemModel.hpp +++ b/GridKit/Model/PowerElectronics/SubsystemModel.hpp @@ -12,14 +12,17 @@ #include #include #include +#include #include namespace GridKit { template - class SubsystemModel : public CircuitComponent + class SubsystemModel : public PowerElectronicsModel { + + using SystemModel = PowerElectronicsModel; using RealT = typename CircuitComponent::RealT; using CsrMatrixT = typename CircuitComponent::CsrMatrixT; using component_type = CircuitComponent; @@ -27,22 +30,30 @@ namespace GridKit using ForcingData = std::pair, std::vector>; using TimeFunction = std::function; - 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 SystemModel::abs_tol_; + using SystemModel::allocated_; + using SystemModel::allocateVectors; + using SystemModel::alpha_; + using SystemModel::f_; + using SystemModel::f_int_; + using SystemModel::n_extern_; + using SystemModel::n_intern_; + using SystemModel::nnz_; + using SystemModel::size_; + using SystemModel::tag_; + using SystemModel::time_; + using SystemModel::y_; + using SystemModel::y_int_; + using SystemModel::yp_; + using SystemModel::yp_int_; + + using SystemModel::components_; + using SystemModel::csr_jac_; + using SystemModel::jac_call_count_; + using SystemModel::map_to_csr_; + using SystemModel::neg1_; + using SystemModel::nodes_; + using SystemModel::use_jac_; public: /** @@ -51,29 +62,16 @@ namespace GridKit * @post System model parameters set as default */ - SubsystemModel() + SubsystemModel(bool use_jac = false) : SystemModel(use_jac) { - // Set system model parameters as default - use_jac_ = false; } - virtual ~SubsystemModel() + ~SubsystemModel() override { - } - - bool hasJacobian() final - { - if (!this->use_jac_) - return false; - - for (const auto& component : components_) - { - if (!component->hasJacobian()) - { - return false; - } - } - return true; + // SubsystemModel does not own components_/nodes_ — they belong to (and are + // deleted by) the parent system model. + components_.clear(); + nodes_.clear(); } int allocate() override @@ -236,25 +234,6 @@ namespace GridKit return 0; } - /** - * @brief Set intial y and y' of each component - * - * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable - */ - int initialize() final - { - // Initialize components - for (const auto& component : components_) - { - component->initialize(); - } - y_.setDataUpdated(); - yp_.setDataUpdated(); - this->distributeVectors(); - - return 0; - } - /** * @brief Distribute y and y' to each component based of node connection graph * @@ -314,207 +293,6 @@ namespace GridKit return 0; } - int tagDifferentiable() final - { - return 0; - } - - /** - * @brief Evaluate Residuals at each component then collect them - * - * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable - */ - int evaluateInternalResidual() final - { - auto* f = f_.getData(); - - for (IdxT i = 0; i < this->getInternalSize(); i++) - { - f[i] = 0.0; - } - - this->distributeVectors(); - - // Update system residual vector - - // Evaluate component internal residuals - this is embarassingly parallel - for (component_type* component : components_) - { - if (int err_code = component->evaluateInternalResidual()) - return err_code; - } - - for (component_type* component : components_) - { - - if (int err_code = component->evaluateExternalResidual()) - return err_code; - - const auto* residual = component->getResidual().getData(); - const auto& externals = component->getExternIndices(); - - for (size_t j : externals) - { - //@todo should do a different grounding check - if (component->getNodeConnection(j) != neg1_ && component->getNodeConnection(j) < this->getInternalSize()) - { - f[component->getNodeConnection(j)] += residual[j]; - } - } - } - - f_.setDataUpdated(); - - return 0; - } - - /** - * @todo implement this for nested systems - */ - int evaluateExternalResidual() final - { - return 0; - } - - /** - * @brief Creates the system Jacobian representing \alpha dF/dy' + dF/dy - * - * - * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable - */ - int evaluateJacobian() final - { - - distributeVectors(); - - // Zero out values - RealT* vals = csr_jac_->getValues(); - for (IdxT i = 0; i < csr_jac_->getNnz(); ++i) - { - vals[i] = 0.0; - } - - // Update CSR values from component Jacobians - IdxT counter = 0; - for (const auto& component : components_) - { - component->evaluateJacobian(); - - const IdxT* r = component->jacobianCooRows(); - const IdxT* c = component->jacobianCooCols(); - const RealT* v = component->jacobianCooValues(); - IdxT nnz = component->nnz(); - - for (IdxT i = 0; i < nnz; ++i) - { - - const IdxT row = component->getNodeConnection(r[i]); - const IdxT col = component->getNodeConnection(c[i]); - - const bool is_internal_entry = row != neg1_ && col != neg1_ && row < n_intern_ && col < n_intern_; - - if (!is_internal_entry) - { - continue; - } - - vals[map_to_csr_[counter]] += v[i]; - ++counter; - } - } - - jac_call_count_++; - return 0; - } - - /** - * @brief Evaluate integrands for the system quadratures. - */ - int evaluateIntegrand() final - { - return 0; - } - - /** - * @brief Initialize system adjoint. - * - * Updates variables and optimization parameters, then initializes - * adjoints locally and copies them to the system adjoint vector. - */ - int initializeAdjoint() final - { - return 0; - } - - /** - * @brief Compute adjoint residual for the system model. - * - * - */ - int evaluateAdjointResidual() final - { - return 0; - } - - /** - * @brief Evaluate adjoint integrand for the system model. - * - * - */ - int evaluateAdjointIntegrand() final - { - 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. - */ - int setAbsoluteTolerance(RealT rel_tol) final - { - abs_tol_.setToConst(static_cast(rel_tol)); - return 0; - } - - /** - * @brief Distribute time and time scaling for each component - * - * @param t - * @param a - */ - void updateTime(RealT t, RealT a) final - { - for (const auto& component : components_) - { - component->updateTime(t, a); - } - time_ = t; - alpha_ = a; - } - - CsrMatrixT* getCsrJacobian() const override - { - return csr_jac_; - } - - void addComponent(component_type* component) - { - components_.push_back(component); - } - - void addNode(node_type* node) - { - nodes_.push_back(node); - } - int mapGlobalToLocal() { for (auto* component : components_) @@ -642,21 +420,17 @@ namespace GridKit forcing_function_ = std::move(function); } - std::unordered_map& getInternalMap() + const std::unordered_map& getInternalMap() const { return internal_map_; } - std::unordered_map& getExternalMap() + const std::unordered_map& getExternalMap() const { return external_map_; } private: - static constexpr IdxT neg1_ = INVALID_INDEX; - - std::vector components_; - std::vector nodes_; std::unordered_map internal_map_; std::unordered_map external_map_; std::vector external_indices_; @@ -667,12 +441,6 @@ namespace GridKit std::optional forcing_function_; - IdxT* map_to_csr_{nullptr}; - CsrMatrixT* csr_jac_{nullptr}; - - int jac_call_count_{0}; - bool use_jac_; - }; // class SubsystemModel -} // namespace GridKit +} // namespace GridKit \ No newline at end of file diff --git a/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp b/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp index 1906b760c..23859d440 100644 --- a/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp +++ b/GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp @@ -23,6 +23,7 @@ namespace GridKit using component_type = CircuitComponent; using node_type = PowerElectronics::NodeBase; + protected: using CircuitComponent::size_; using CircuitComponent::n_intern_; using CircuitComponent::n_extern_; @@ -41,17 +42,6 @@ namespace GridKit using CircuitComponent::allocateVectors; public: - /** - * @brief Default constructor for the system model - * - * @post System model parameters set as default - */ - PowerElectronicsModel() - { - // By default don't use the jacobian - use_jac_ = false; - } - /** * @brief Constructor for the system model * @@ -119,7 +109,7 @@ namespace GridKit * * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable */ - int allocate() final + int allocate() override { size_t component_internal_size = 0; for (component_type* comp : components_) @@ -285,7 +275,7 @@ namespace GridKit * * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable */ - int initialize() final + int initialize() { // Initialize components for (const auto& component : components_) @@ -306,7 +296,7 @@ namespace GridKit * * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable */ - int distributeVectors() + virtual int distributeVectors() { const auto* y_system = y_.getData(); const auto* yp_system = yp_.getData(); @@ -336,7 +326,7 @@ namespace GridKit return 0; } - int tagDifferentiable() final + int tagDifferentiable() { return 0; } @@ -364,7 +354,7 @@ namespace GridKit * * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable */ - int evaluateInternalResidual() final + int evaluateInternalResidual() override { auto* f = f_.getData(); @@ -395,7 +385,7 @@ namespace GridKit for (size_t j : externals) { //@todo should do a different grounding check - if (component->getNodeConnection(j) != neg1_) + if (component->getNodeConnection(j) != neg1_ && component->getNodeConnection(j) < this->size()) { f[component->getNodeConnection(j)] += residual[j]; } @@ -423,7 +413,7 @@ namespace GridKit * * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable */ - int evaluateJacobian() final + int evaluateJacobian() override { distributeVectors(); @@ -447,11 +437,18 @@ namespace GridKit for (IdxT i = 0; i < nnz; ++i) { - if (component->getNodeConnection(r[i]) != neg1_ && component->getNodeConnection(c[i]) != neg1_) + const IdxT row = component->getNodeConnection(r[i]); + const IdxT col = component->getNodeConnection(c[i]); + + const bool is_internal_entry = row != neg1_ && col != neg1_ && row < n_intern_ && col < n_intern_; + + if (!is_internal_entry) { - vals[map_to_csr_[counter]] += v[i]; - ++counter; + continue; } + + vals[map_to_csr_[counter]] += v[i]; + ++counter; } } @@ -531,7 +528,7 @@ namespace GridKit allocated_ = false; } - private: + protected: static constexpr IdxT neg1_ = INVALID_INDEX; std::vector components_; From b48a401756cb6a1785df7dfb1a1595f02c72ce9e Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Thu, 23 Jul 2026 05:17:43 +0000 Subject: [PATCH 30/34] Apply pre-commit fixes --- GridKit/Model/PowerElectronics/SubsystemModel.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/GridKit/Model/PowerElectronics/SubsystemModel.hpp b/GridKit/Model/PowerElectronics/SubsystemModel.hpp index 35bb0eab9..8e7d920ad 100644 --- a/GridKit/Model/PowerElectronics/SubsystemModel.hpp +++ b/GridKit/Model/PowerElectronics/SubsystemModel.hpp @@ -62,7 +62,8 @@ namespace GridKit * @post System model parameters set as default */ - SubsystemModel(bool use_jac = false) : SystemModel(use_jac) + SubsystemModel(bool use_jac = false) + : SystemModel(use_jac) { } @@ -443,4 +444,4 @@ namespace GridKit }; // class SubsystemModel -} // namespace GridKit \ No newline at end of file +} // namespace GridKit From a2876245d2249ed52d8a3133c12e4f7653623449 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Fri, 24 Jul 2026 04:55:47 +0000 Subject: [PATCH 31/34] Updated SubsystemModel and Partition interfaces --- .../BusPartitionInterface.cpp | 15 +- .../BusPartitionInterface.hpp | 2 - .../Model/PowerElectronics/SubsystemModel.hpp | 312 +++++++++++++++--- 3 files changed, 271 insertions(+), 58 deletions(-) diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp index 070c190f6..578493931 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp @@ -46,6 +46,7 @@ namespace GridKit const IdxT bus_i = bus.getNodeConnection(0); const IdxT bus_j = bus.getNodeConnection(1); + nnz_ = 0; for (IdxT k = 0; k < component_.nnz(); ++k) { const IdxT row_node = component_.getNodeConnection(cooRow[k]); @@ -104,7 +105,7 @@ namespace GridKit << "), Component(ID=" << component_.getIDcomponent() << "). Please verify connection-node mappings and internal/external index assignments." << std::endl; - assert(false); + return 1; } const auto n = component_.getInternalSize(); @@ -146,7 +147,7 @@ namespace GridKit } /** - * @brief Eval Micro Load + * @brief Eval Internal Residual */ template int BusPartitionInterface::evaluateInternalResidual() @@ -171,7 +172,7 @@ namespace GridKit for (size_t i = 0; i < static_cast(component_.size()); ++i) { - if (extern_indices.contains(i)) + if (extern_indices.contains(static_cast(i))) { component_y[external] = y[i]; component_yp[external] = yp[i]; @@ -185,12 +186,16 @@ namespace GridKit } } + component_.y().setDataUpdated(); + component_.y().setDataUpdated(); + component_.evaluateResidual(); const auto* residual = component_.getResidual().getData(); // TODO: This assumes that external variables are ordered after all internal - // variables in the local indexing. To make this more robust, we need to get rid of this assumption. + // variables in the indexing. To make this more robust, we need to get rid of this assumption + // (although true for all components that we have in GridKit). f[bus_port_i_] = residual[bus_port_i_]; f[bus_port_j_] = residual[bus_port_j_]; @@ -200,7 +205,7 @@ namespace GridKit } /** - * @brief Generate Jacobian for Micro Load + * @brief Generate Jacobian for * * @tparam ScalarT * @tparam IdxT diff --git a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp index 7244fad4d..93c764b8f 100644 --- a/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp +++ b/GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.hpp @@ -2,8 +2,6 @@ #pragma once -#include - #include #include diff --git a/GridKit/Model/PowerElectronics/SubsystemModel.hpp b/GridKit/Model/PowerElectronics/SubsystemModel.hpp index 8e7d920ad..ff6a25d51 100644 --- a/GridKit/Model/PowerElectronics/SubsystemModel.hpp +++ b/GridKit/Model/PowerElectronics/SubsystemModel.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -21,14 +22,16 @@ namespace GridKit template class SubsystemModel : public PowerElectronicsModel { + public: + using ForcingData = std::tuple, std::vector>; + using TimeFunction = std::function; + protected: using SystemModel = PowerElectronicsModel; using RealT = typename CircuitComponent::RealT; using CsrMatrixT = typename CircuitComponent::CsrMatrixT; using component_type = CircuitComponent; using node_type = PowerElectronics::NodeBase; - using ForcingData = std::pair, std::vector>; - using TimeFunction = std::function; using SystemModel::abs_tol_; using SystemModel::allocated_; @@ -78,9 +81,7 @@ namespace GridKit int allocate() override { - this->createGlobalToInternalMap(); - - this->mapGlobalToLocal(); + hold(); n_intern_ = internal_map_.size(); n_extern_ = external_map_.size(); @@ -102,7 +103,7 @@ namespace GridKit yp_ext_.resize(n_extern_); f_ext_.resize(n_extern_); - external_indices_.resize(n_extern_); + external_data_indices_.resize(n_extern_); // Store the mapping from local subsystem indices back to their global system indices for (const auto [global_idx, local_idx] : internal_map_) @@ -113,7 +114,7 @@ namespace GridKit // Store the global indices of all external coupling variables. for (const auto [global_idx, local_idx] : external_map_) { - external_indices_[local_idx - n_intern_] = global_idx; + external_data_indices_[local_idx - n_intern_] = global_idx; } size_t component_internal_idx = 0; @@ -242,15 +243,12 @@ namespace GridKit * * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable */ - int distributeVectors() + int distributeVectors() override { if (forcing_function_) { - const auto forcing = (*forcing_function_)(time_); - - const auto& y_forcing = forcing.first; - const auto& yp_forcing = forcing.second; + const auto [y_forcing, yp_forcing] = (*forcing_function_)(time_); assert(y_forcing.size() == y_ext_.size()); assert(yp_forcing.size() == yp_ext_.size()); @@ -294,8 +292,232 @@ namespace GridKit return 0; } + /** + * @brief Add a component to the subsystem. + * + * Rejected while connections are in the local-indexed state, since the + * component's stored connection indices would otherwise be interpreted + * inconsistently with the rest of the subsystem. Call release() first. + * + * @param[in] component Component to add. + */ + void addComponent(component_type* component) + { + if (is_comp_in_local_state) + { + std::cerr << "SubsystemModel::addComponent: cannot add component while " + "in local-indexed state. Call release() first.\n"; + return; + } + + SystemModel::addComponent(component); + } + + /** + * @brief Add a node to the subsystem. + * + * Rejected while connections are in the local-indexed state, since the + * node's stored connection indices would otherwise be interpreted + * inconsistently with the rest of the subsystem. Call release() first. + * + * @param[in] node Node to add. + */ + void addNode(node_type* node) + { + if (is_comp_in_local_state) + { + std::cerr << "SubsystemModel::addNode: cannot add node while in " + "local-indexed state. Call release() first.\n"; + return; + } + + SystemModel::addNode(node); + } + + /** + * @brief Acquire the subsystem's global-to-local index mappings. + * + * Builds the internal/external index maps via buildIndexMappings(), + * then converts component/node connections from global to local + * indices via mapGlobalToLocal(). + * + * Call this after modifying subsystem topology (adding or removing + * components/nodes) and before allocate(), to (re)establish local + * indexing. Pairs with release(), which undoes this. + * + * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable + */ + int hold() + { + buildIndexMappings(); + + if (int err_code = mapGlobalToLocal()) + { + return err_code; + } + + return 0; + } + + /** + * @brief Release the subsystem's global-to-local index mappings. + * + * If components/nodes currently hold local indices, they are first + * converted back to their original global indices via + * mapLocalToGlobal(). The internal/external index maps built by + * buildIndexMappings() are then cleared, and the model is marked as + * not allocated. + * + * + * Call this before modifying subsystem topology (adding or removing + * components/nodes), so stale local indices aren't left dangling. + * + * @return int 0 if successful, positive if there's a recoverable error, negative if unrecoverable + */ + int release() + { + if (int err_code = mapLocalToGlobal()) + { + return err_code; + } + + internal_map_.clear(); + external_map_.clear(); + + allocated_ = false; + + return 0; + } + + const std::vector& getExternalDataIndices() + { + return external_data_indices_; + } + + std::vector& getExternalDataY() + { + return y_ext_; + } + + std::vector& getExternalDataYP() + { + return yp_ext_; + } + + std::vector& getExternalDataF() + { + return f_ext_; + } + + void setTimeFunction(TimeFunction function) + { + forcing_function_ = std::move(function); + } + + const std::unordered_map& getInternalMap() const + { + return internal_map_; + } + + const std::unordered_map& getExternalMap() const + { + return external_map_; + } + + private: + /** + * @brief Replace local subsystem connection indices with their original global indices + * for every component and node. + * + * Inverse of mapGlobalToLocal(). Internal connections (index < internal + * size) are mapped back through this subsystem's own node-connection + * table; external connections are mapped back through + * @c external_data_indices_. Entries equal to @c neg1_ represent no + * connection and are left unchanged. + * + * @return Always returns 0. + */ + int mapLocalToGlobal() + { + if (!is_comp_in_local_state) + { + return 0; + } + + for (auto* component : components_) + { + + for (IdxT i = 0; i < component->size(); i++) + { + IdxT index = component->getNodeConnection(i); + + if (index == neg1_) + { + continue; + } + else if (index < this->getInternalSize()) + { + component->setExternalConnectionNodes(i, this->getNodeConnection(index)); + } + else + { + component->setExternalConnectionNodes(i, external_data_indices_[index - this->getInternalSize()]); + } + } + } + + for (auto* node : nodes_) + { + + for (IdxT i = 0; i < node->size(); i++) + { + IdxT index = node->getNodeConnection(i); + + if (index == neg1_) + { + continue; + } + else if (index < this->getInternalSize()) + { + node->setExternalConnectionNodes(i, this->getNodeConnection(index)); + } + else + { + node->setExternalConnectionNodes(i, external_data_indices_[index - this->getInternalSize()]); + } + } + } + + is_comp_in_local_state = false; + + return 0; + } + + /** + * @brief Replace global connection indices with local subsystem indices for every component + * and node. + * + * After the internal and external maps have been constructed, each component + * and node still stores the original global connection indices. This function + * traverses every connection and replaces each global index with its + * corresponding local subsystem index. + * + * Internal connections are mapped using @c internal_map_, while connections + * that reference variables outside the subsystem are mapped using + * @c external_map_. Entries equal to @c neg1_ represent no connection and + * are left unchanged. + * + * @return Always returns 0. + */ + int mapGlobalToLocal() { + + if (is_comp_in_local_state) + { + return 0; + } + for (auto* component : components_) { @@ -340,12 +562,34 @@ namespace GridKit } } + is_comp_in_local_state = true; + return 0; } - void createGlobalToInternalMap() + /** + * @brief Construct the mappings from global variable indices to local + * subsystem indices. + * + * The subsystem stores its variables in a contiguous local ordering. This + * function assigns each global variable index a corresponding local index and + * separates them into internal and external variables. + * + * Internal variables are those owned by this subsystem, while external + * variables are owned by neighboring subsystems but are required for residual + * and Jacobian evaluation. + */ + void buildIndexMappings() { + if (is_comp_in_local_state) + { + return; + } + + internal_map_.clear(); + external_map_.clear(); + size_t component_internal_idx = 0; // First pass: Map global component indices to local subsystem indices. for (component_type* comp : components_) @@ -396,45 +640,9 @@ namespace GridKit } } - std::vector& getExternalIndices() - { - return external_indices_; - } - - std::vector& getExternalDataY() - { - return y_ext_; - } - - std::vector& getExternalDataYP() - { - return yp_ext_; - } - - std::vector& getExternalDataF() - { - return f_ext_; - } - - void setTimeFunction(TimeFunction function) - { - forcing_function_ = std::move(function); - } - - const std::unordered_map& getInternalMap() const - { - return internal_map_; - } - - const std::unordered_map& getExternalMap() const - { - return external_map_; - } - - private: std::unordered_map internal_map_; std::unordered_map external_map_; - std::vector external_indices_; + std::vector external_data_indices_; std::vector y_ext_; std::vector yp_ext_; @@ -442,6 +650,8 @@ namespace GridKit std::optional forcing_function_; + bool is_comp_in_local_state{false}; + }; // class SubsystemModel -} // namespace GridKit +} // namespace GridKit \ No newline at end of file From dd82bb695799f3bed04ec20e3cb7421f2fa85b86 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Fri, 24 Jul 2026 05:05:37 +0000 Subject: [PATCH 32/34] Updated examples to reflect new changes in subsystem model and partition interfaces --- .../PowerElectronics/Partition/CMakeLists.txt | 76 ++++++++++++++----- .../PowerElectronics/Partition/Partition.cpp | 4 +- .../Partition/PartitionMicrogrid.cpp | 31 ++++++-- .../Partition/PartitionScaleMicrogrid.cpp | 4 +- 4 files changed, 86 insertions(+), 29 deletions(-) diff --git a/examples/PowerElectronics/Partition/CMakeLists.txt b/examples/PowerElectronics/Partition/CMakeLists.txt index 6f2f633d6..03d45b6f5 100644 --- a/examples/PowerElectronics/Partition/CMakeLists.txt +++ b/examples/PowerElectronics/Partition/CMakeLists.txt @@ -1,26 +1,64 @@ -find_package(OpenMP REQUIRED) +find_package(OpenMP) add_executable(partition Partition.cpp) + target_link_libraries( - partition GridKit::solvers_dyn GridKit::power_elec_partition_interfaces) + partition + PRIVATE + GridKit::solvers_dyn + GridKit::power_elec_partition_interfaces +) add_executable(partitionMicrogrid PartitionMicrogrid.cpp) + target_link_libraries( partitionMicrogrid - GridKit::power_elec_disgen - GridKit::power_elec_microline - GridKit::power_elec_microload - GridKit::solvers_dyn - GridKit::power_elec_microbusdq - GridKit::power_elec_partition_interfaces) - -add_executable(PartitionScaleMicrogrid PartitionScaleMicrogrid.cpp) -target_link_libraries( - PartitionScaleMicrogrid - GridKit::power_elec_disgen - GridKit::power_elec_microline - GridKit::power_elec_microload - GridKit::solvers_dyn - GridKit::power_elec_microbusdq - GridKit::power_elec_partition_interfaces - OpenMP::OpenMP_CXX) + PRIVATE + GridKit::power_elec_disgen + GridKit::power_elec_microline + GridKit::power_elec_microload + GridKit::solvers_dyn + GridKit::power_elec_microbusdq + GridKit::power_elec_partition_interfaces +) + +add_test( + NAME PartitionMicrogrid + COMMAND partitionMicrogrid +) + +install( + TARGETS + partition + partitionMicrogrid + RUNTIME DESTINATION bin +) + +if(OpenMP_CXX_FOUND) + add_executable( + PartitionScaleMicrogrid + PartitionScaleMicrogrid.cpp + ) + + target_link_libraries( + PartitionScaleMicrogrid + PRIVATE + GridKit::power_elec_disgen + GridKit::power_elec_microline + GridKit::power_elec_microload + GridKit::solvers_dyn + GridKit::power_elec_microbusdq + GridKit::power_elec_partition_interfaces + OpenMP::OpenMP_CXX + ) + + add_test( + NAME PartitionScaleMicrogrid + COMMAND PartitionScaleMicrogrid + ) + + install( + TARGETS PartitionScaleMicrogrid + RUNTIME DESTINATION bin + ) +endif() \ No newline at end of file diff --git a/examples/PowerElectronics/Partition/Partition.cpp b/examples/PowerElectronics/Partition/Partition.cpp index 93f14cbc8..05feee692 100644 --- a/examples/PowerElectronics/Partition/Partition.cpp +++ b/examples/PowerElectronics/Partition/Partition.cpp @@ -75,8 +75,8 @@ int main(int /* argc */, char const** /* argv */) for (size_t i = 0; i < partition->getExternSize(); i++) { - partition->getExternalDataY()[i] = y[partition->getExternalIndices()[i]]; - partition->getExternalDataYP()[i] = yp[partition->getExternalIndices()[i]]; + partition->getExternalDataY()[i] = y[partition->getExternalDataIndices()[i]]; + partition->getExternalDataYP()[i] = yp[partition->getExternalDataIndices()[i]]; } auto* partition_y = partition->y().getData(); diff --git a/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp b/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp index d72c50f4e..ba9e7df64 100644 --- a/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp +++ b/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp @@ -90,6 +90,8 @@ int main() double Lload2 = 1.0 / (2.0 * M_PI * 50.0); using SignalNode = GridKit::PowerElectronics::SignalNode; + using Subsystem = GridKit::SubsystemModel; + SignalNode dg_signal; sysmodel->addNode(&dg_signal); @@ -167,8 +169,8 @@ int main() sysmodel->allocate(); - GridKit::SubsystemModel* partition1 = new GridKit::SubsystemModel(); - GridKit::SubsystemModel* partition2 = new GridKit::SubsystemModel(); + Subsystem* partition1 = new Subsystem(); + Subsystem* partition2 = new Subsystem(); GridKit::MicrogridLine l2copy(*l2); GridKit::BusPartitionInterface* busInterface1 = new GridKit::BusPartitionInterface(bus2, l2copy, 14); @@ -232,13 +234,30 @@ int main() { partition->allocate(); + // test hold and release methods + partition->release(); + partition->hold(); + partition->updateTime(2, 5); - for (size_t i = 0; i < partition->getExternSize(); i++) + // Test setTimeFunction function + auto forcing = [&]([[maybe_unused]] double t) -> Subsystem::ForcingData { - partition->getExternalDataY()[i] = y[partition->getExternalIndices()[i]]; - partition->getExternalDataYP()[i] = yp[partition->getExternalIndices()[i]]; - } + auto ext_size = partition->getExternSize(); + + std::vector y_ext(ext_size); + std::vector yp_ext(ext_size); + + for (size_t i = 0; i < partition->getExternSize(); i++) + { + y_ext[i] = y[partition->getExternalDataIndices()[i]]; + yp_ext[i] = yp[partition->getExternalDataIndices()[i]]; + } + + return {y_ext, yp_ext}; + }; + + partition->setTimeFunction(forcing); auto* partition_y = partition->y().getData(); auto* partition_yp = partition->yp().getData(); diff --git a/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp b/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp index 2a6da84d0..13b10a4ad 100644 --- a/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp +++ b/examples/PowerElectronics/Partition/PartitionScaleMicrogrid.cpp @@ -436,8 +436,8 @@ RunResult printMicrogridSystems(index_type N_size, index_type num_partitions) // Distribute external variables for (size_t i = 0; i < partition->getExternSize(); i++) { - partition->getExternalDataY()[i] = y[partition->getExternalIndices()[i]]; - partition->getExternalDataYP()[i] = yp[partition->getExternalIndices()[i]]; + partition->getExternalDataY()[i] = y[partition->getExternalDataIndices()[i]]; + partition->getExternalDataYP()[i] = yp[partition->getExternalDataIndices()[i]]; } auto* partition_y = partition->y().getData(); From 060c5250d06c43ac44ac1eb93a4c4d54c0e5adc1 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Fri, 24 Jul 2026 05:15:31 +0000 Subject: [PATCH 33/34] Apply pre-commit fixes --- .../Model/PowerElectronics/SubsystemModel.hpp | 2 +- .../PowerElectronics/Partition/CMakeLists.txt | 68 ++++++------------- 2 files changed, 23 insertions(+), 47 deletions(-) diff --git a/GridKit/Model/PowerElectronics/SubsystemModel.hpp b/GridKit/Model/PowerElectronics/SubsystemModel.hpp index ff6a25d51..0c0cbcab5 100644 --- a/GridKit/Model/PowerElectronics/SubsystemModel.hpp +++ b/GridKit/Model/PowerElectronics/SubsystemModel.hpp @@ -654,4 +654,4 @@ namespace GridKit }; // class SubsystemModel -} // namespace GridKit \ No newline at end of file +} // namespace GridKit diff --git a/examples/PowerElectronics/Partition/CMakeLists.txt b/examples/PowerElectronics/Partition/CMakeLists.txt index 03d45b6f5..e428f5908 100644 --- a/examples/PowerElectronics/Partition/CMakeLists.txt +++ b/examples/PowerElectronics/Partition/CMakeLists.txt @@ -4,61 +4,37 @@ add_executable(partition Partition.cpp) target_link_libraries( partition - PRIVATE - GridKit::solvers_dyn - GridKit::power_elec_partition_interfaces -) + PRIVATE GridKit::solvers_dyn GridKit::power_elec_partition_interfaces) add_executable(partitionMicrogrid PartitionMicrogrid.cpp) target_link_libraries( partitionMicrogrid - PRIVATE - GridKit::power_elec_disgen - GridKit::power_elec_microline - GridKit::power_elec_microload - GridKit::solvers_dyn - GridKit::power_elec_microbusdq - GridKit::power_elec_partition_interfaces -) + PRIVATE GridKit::power_elec_disgen + GridKit::power_elec_microline + GridKit::power_elec_microload + GridKit::solvers_dyn + GridKit::power_elec_microbusdq + GridKit::power_elec_partition_interfaces) -add_test( - NAME PartitionMicrogrid - COMMAND partitionMicrogrid -) +add_test(NAME PartitionMicrogrid COMMAND partitionMicrogrid) -install( - TARGETS - partition - partitionMicrogrid - RUNTIME DESTINATION bin -) +install(TARGETS partition partitionMicrogrid RUNTIME DESTINATION bin) if(OpenMP_CXX_FOUND) - add_executable( - PartitionScaleMicrogrid - PartitionScaleMicrogrid.cpp - ) + add_executable(PartitionScaleMicrogrid PartitionScaleMicrogrid.cpp) target_link_libraries( PartitionScaleMicrogrid - PRIVATE - GridKit::power_elec_disgen - GridKit::power_elec_microline - GridKit::power_elec_microload - GridKit::solvers_dyn - GridKit::power_elec_microbusdq - GridKit::power_elec_partition_interfaces - OpenMP::OpenMP_CXX - ) - - add_test( - NAME PartitionScaleMicrogrid - COMMAND PartitionScaleMicrogrid - ) - - install( - TARGETS PartitionScaleMicrogrid - RUNTIME DESTINATION bin - ) -endif() \ No newline at end of file + PRIVATE GridKit::power_elec_disgen + GridKit::power_elec_microline + GridKit::power_elec_microload + GridKit::solvers_dyn + GridKit::power_elec_microbusdq + GridKit::power_elec_partition_interfaces + OpenMP::OpenMP_CXX) + + add_test(NAME PartitionScaleMicrogrid COMMAND PartitionScaleMicrogrid) + + install(TARGETS PartitionScaleMicrogrid RUNTIME DESTINATION bin) +endif() From a375b1fa65b64a7efc6159a16c434a0360f3c187 Mon Sep 17 00:00:00 2001 From: abdourahmanbarry Date: Fri, 24 Jul 2026 20:02:23 +0000 Subject: [PATCH 34/34] Addressed leaks --- examples/PowerElectronics/Partition/PartitionMicrogrid.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp b/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp index ba9e7df64..c9a984950 100644 --- a/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp +++ b/examples/PowerElectronics/Partition/PartitionMicrogrid.cpp @@ -326,6 +326,7 @@ int main() delete sysmodel; delete partition1; delete partition2; + delete busInterface1; return 0; }