Skip to content

Initial Implementation of Subsystem Model for Partition Simulation - #492

Open
abdourahmanbarry wants to merge 53 commits into
developfrom
abdou/partitioning_microgrid
Open

Initial Implementation of Subsystem Model for Partition Simulation#492
abdourahmanbarry wants to merge 53 commits into
developfrom
abdou/partitioning_microgrid

Conversation

@abdourahmanbarry

@abdourahmanbarry abdourahmanbarry commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Description

In this PR, we introduce the initial implementation of the SubsystemModel for partitioned Power Electronics simulation. The implementation provides the infrastructure required to partition Power Electronic networks, and to evaluate subsystem residuals and Jacobians independently. This lays the foundation for implementing co-simulation methods in future pull requests.

Proposed changes

  • We added a SubsystemModel class to represent an individual partition and a BusPartitionInterface component to mark partition boundaries.
  • Implemented residual and Jacobian evaluation for subsystem models.
  • Added support for user-defined coupling functions required for solving subsystems with multi-stage co-simulation methods.

Checklist

  • All tests pass.
  • Code compiles cleanly with flags -Wall -Wpedantic -Wconversion -Wextra.
  • The new code follows GridKit™ style guidelines.
  • There are unit tests for the new code.
  • The new code is documented.
  • The feature branch is rebased with respect to the target branch.
  • I have updated CHANGELOG.md to reflect the changes in this PR. If this is a minor PR that is part of a larger fix already included in the file, state so.

@abdourahmanbarry
abdourahmanbarry force-pushed the abdou/partitioning_microgrid branch from 85a516d to 01a410b Compare July 19, 2026 08:27
@abdourahmanbarry abdourahmanbarry self-assigned this Jul 23, 2026
@abdourahmanbarry
abdourahmanbarry force-pushed the abdou/partitioning_microgrid branch from 66c58ad to b48a401 Compare July 24, 2026 02:46
@abdourahmanbarry
abdourahmanbarry force-pushed the abdou/partitioning_microgrid branch from a375b1f to f65baeb Compare August 3, 2026 05:16
@abdourahmanbarry
abdourahmanbarry marked this pull request as ready for review August 6, 2026 05:57
@abdourahmanbarry

Copy link
Copy Markdown
Collaborator Author

This pull request is ready for review.

@pelesh pelesh added enhancement New feature or request new solver labels Aug 7, 2026
@pelesh pelesh added this to the Release 0.3 milestone Aug 7, 2026
Comment thread examples/PowerElectronics/Partition/CMakeLists.txt Outdated
Comment thread examples/PowerElectronics/Partition/HiresBus.hpp Outdated
Comment thread examples/PowerElectronics/Partition/HiresBus.hpp Outdated
Comment thread examples/PowerElectronics/Partition/Partition.cpp Outdated
Comment thread examples/PowerElectronics/Partition/Partition.cpp Outdated
Comment thread GridKit/Model/PowerElectronics/SubsystemModel.hpp
Comment thread GridKit/Model/PowerElectronics/SubsystemModel.hpp Outdated
Comment thread GridKit/Model/PowerElectronics/SubsystemModel.hpp Outdated
Comment thread GridKit/Model/PowerElectronics/SubsystemModel.hpp Outdated
Comment thread GridKit/Model/PartitionEvaluator.hpp Outdated
@abdourahmanbarry
abdourahmanbarry force-pushed the abdou/partitioning_microgrid branch from e96184a to 98be2e0 Compare August 11, 2026 18:28
abdourahmanbarry and others added 10 commits August 11, 2026 18:37
- Improved subsystem residual and Jacobian validation against the full-system model.
- Updated BusPartitionInterface to support arbitrary ordering of internal and external component variables.
- Added ownership and cleanup of copied components used by partition interfaces.
- Improved comments and documentation for partitioning, Jacobian verification, and interface behavior.
@abdourahmanbarry
abdourahmanbarry force-pushed the abdou/partitioning_microgrid branch from 98be2e0 to f082543 Compare August 11, 2026 18:52
Comment thread examples/PowerElectronics/Partition/PartitionHires.cpp Outdated

@nkoukpaizan nkoukpaizan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I few initial comments on the Hires example. I'll take a closer look at the partition interface after comments by @alexander-novo have been addressed.

Comment thread examples/PowerElectronics/Partition/HiresBus.hpp Outdated
Comment thread examples/PowerElectronics/Partition/HiresBus.hpp Outdated
Comment thread examples/PowerElectronics/Partition/jac_test_helper.hpp Outdated
Comment thread examples/PowerElectronics/Common/JacTestHelper.hpp
Comment thread examples/PowerElectronics/Partition/PartitionHires.cpp Outdated
Comment thread examples/PowerElectronics/Partition/PartitionHires.cpp Outdated
Comment thread examples/PowerElectronics/Partition/CMakeLists.txt Outdated
Comment thread examples/PowerElectronics/Partition/PartitionHires.cpp Outdated
Comment thread examples/PowerElectronics/Partition/PartitionHires.cpp Outdated
Comment thread GridKit/Model/PowerElectronics/PartitionInterface/CMakeLists.txt Outdated
- add documentation for hires problem and partitioning
- test subsystem jacobian and residuals
- Update CMake file
- Add comments to methods and lambda functions
- added check to ensure only allocated components can be added to model
- Change parameter type in addInterface method to PartitionInterface
- Partition interface can be applied to all bus types, not just MicrogridBus
- New clone functionality  allows users to pass components directly without explicitly copying it
- Update CMake file with dense vector dependency
- Add more documentation
- Move  suitable code from constructor to allocate
- move microgrid network builder section to separate file to facilitate code reuse as more examples dependent on it
- Add partition utility code to minimize code duplication in partition examples.
- Added all helper header files in one location
- Remove remaining Hires example files from Partition folder
- Refactored common code in the Microgrid, ScaleMicrogrid, and ScaleMicrogridArbitrary examples into reusable helper functions
- Improved documentation across the PowerElectronics examples
- Updated CMake files
- Minor format changes
- Updated tests and added documentation for partition interface and SubsystemModel
-  Used size_t for some loops in CircuitComponent

@nkoukpaizan nkoukpaizan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall nice work!

In addition to the specific comments below:

  • With the growing size of this PR, you might want to isolate some of the changes into small PRs that we can quickly review and merge.
  • Please rebase, so CI runs. You might want to hold off on updating CHANGELOG.md until it's closer to ready to merge to reduce the need to rebase.
  • We need to better document how clone() and forcing_data work and how syncing might occur in simulations.
  • I am getting a test failure. Loosening the tolerance would be reasonable, as long as the error sources are well understood and documented.
11: Partition Microgrid Validation
11: ------------------------------
11: Maximum residual error:         2.313046080415393e-14
11: Machine epsilon:                2.220446049250313e-16
11: Residuals matched:              False
1/1 Test #11: PartitionMicrogrid ...............***Failed    0.06 sec

Comment on lines +236 to +244
auto isEqual = [&tolerance](RealT value, RealT reference)
{
if (tolerance)
{
return GridKit::Testing::isEqual(value, reference, *tolerance);
}

return GridKit::Testing::isEqual(value, reference);
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would set the default tolerance for the helper to machine precision and always pass it to GridKit::Testing::isEqual. That would remove the need for this lambda.

@@ -0,0 +1,309 @@
// MicrogridNetwork.hpp

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a welcome change! Consider isolating this into a quick PR to facilitate review and narrow the scope of this one.

Comment on lines +75 to +79
IdxT part_size = q + (j < r ? 1 : 0);
IdxT end = std::min(index + part_size, num_ibrs);

// Add all components belonging to this partition.
for (; index < end; ++index)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some documentation would be helpful for this logic. Consider writing more explicitly.

\left(\frac{dy_4}{dt}+y_4\right)
+\left(0.1y_4-8.32y_2-1.71y_3\right)
+0.02y_4,
\\[6pt]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some rendering issues on GH.

// 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);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

M_PI --> std::numbers::pi_v<RealT> to be consistent with recent changes (#521), though we don't have to be as strict in examples/.

Comment on lines +87 to +149
if (other.jacobian_coo_rows_)
{
jacobian_coo_rows_ = std::make_unique<IdxT[]>(static_cast<size_t>(nnz_));

for (IdxT i = 0; i < nnz_; ++i)
{
jacobian_coo_rows_[static_cast<size_t>(i)] = other.jacobian_coo_rows_[static_cast<size_t>(i)];
}
}

/*
* Deep-copy the COO Jacobian column indices.
*/
if (other.jacobian_coo_cols_)
{
jacobian_coo_cols_ = std::make_unique<IdxT[]>(static_cast<size_t>(nnz_));

for (IdxT i = 0; i < nnz_; ++i)
{
jacobian_coo_cols_[static_cast<size_t>(i)] = other.jacobian_coo_cols_[static_cast<size_t>(i)];
}
}

/*
* Deep-copy the COO Jacobian values.
*/
if (other.jacobian_coo_values_)
{
jacobian_coo_values_ = std::make_unique<RealT[]>(static_cast<size_t>(nnz_));

for (IdxT i = 0; i < nnz_; ++i)
{
jacobian_coo_values_[static_cast<size_t>(i)] = other.jacobian_coo_values_[static_cast<size_t>(i)];
}
}

if (size_ > 0)
{
y_ext_ = std::make_unique<const ScalarT*[]>(static_cast<size_t>(size_));
yp_ext_ = std::make_unique<const ScalarT*[]>(static_cast<size_t>(size_));
f_ext_ = std::make_unique<ScalarT*[]>(static_cast<size_t>(size_));

for (IdxT i = 0; i < size_; ++i)
{
y_ext_[i] = nullptr;
yp_ext_[i] = nullptr;
f_ext_[i] = nullptr;
}
}

// State, state derivative, residual, and absolute tolerance.
copyVector(y_, other.y_);
copyVector(yp_, other.yp_);
copyVector(f_, other.f_);
copyVector(abs_tol_, other.abs_tol_);
copyVector(g_, other.g_);
copyVector(yB_, other.yB_);
copyVector(ypB_, other.ypB_);
copyVector(fB_, other.fB_);
copyVector(gB_, other.gB_);
copyVector(param_, other.param_);
copyVector(param_up_, other.param_up_);
copyVector(param_lo_, other.param_lo_);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect the cloning and syncing of the states to be different operations. One would need to keep things synced as the simulation progresses.

#include <GridKit/Model/PowerElectronics/SystemModelPowerElectronics.hpp>
#include <GridKit/ScalarTraits.hpp>

namespace GridKit

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a @todo item for namespace PowerElectronics. I see this applies to all PowerElectronics models. A quick PR for this update would be nice too!

Comment on lines +383 to +389
if (!is_internal_entry)
{
vals[map_to_csr_[counter]] += v[i];
++counter;
continue;
}

vals[map_to_csr_[counter]] += v[i];
++counter;

@nkoukpaizan nkoukpaizan Aug 24, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is clearer to me. Multiple instances of this.

Suggested change
if (!is_internal_entry)
{
vals[map_to_csr_[counter]] += v[i];
++counter;
continue;
}
vals[map_to_csr_[counter]] += v[i];
++counter;
if (is_internal_entry)
{
vals[map_to_csr_[counter]] += v[i];
++counter;
}

{

template <class ScalarT, typename IdxT>
class SubsystemModel : public PowerElectronicsModel<ScalarT, IdxT>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a todo to make the names more intuitive, potentially renaming the base class.

Comment on lines +792 to +820
/**
*@brief Maps global system indices to local subsystem indices for internal variables.
*/
std::unordered_map<IdxT, IdxT> internal_map_;

/**
* @brief Maps global system indices to local subsystem indices for external variables.
*/
std::unordered_map<IdxT, IdxT> external_map_;

/**
* @brief Global system index corresponding to each entry in the external subsystem vectors.
*/
std::vector<IdxT> external_data_indices_;

/**
* @brief subsystem external State, derivative, and residual vectors.
*/
std::vector<ScalarT> y_ext_data_;

/**
* @brief subsystem external derivative
*/
std::vector<ScalarT> yp_ext_data_;

/**
* @brief subsystem external derivative
*/
std::vector<ScalarT> f_ext_data_;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we use the same storage types as the base classes, e.g., GridKit::LinearAlgebra::Vector?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request new solver

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants