Skip to content

Add Subsystem and Partition Interfaces for PowerElectronics - #560

Open
abdourahmanbarry wants to merge 38 commits into
developfrom
abdou/subsystem_model
Open

abdourahmanbarry wants to merge 38 commits into
developfrom
abdou/subsystem_model

Conversation

@abdourahmanbarry

Copy link
Copy Markdown
Collaborator

Description

In this PR, we implement SubsystemModel for partitioned Power Electronics simulation. The implementation provides the infrastructure required to partition Power Electronics networks, and to evaluate subsystem residuals and Jacobians independently.

This is the third of four stacked pull requests that split PR #492 into simpler, more manageable chunks.

Proposed changes

We added a SubsystemModel class to represent an individual partition and a BusPartitionInterface component to mark partition boundaries. Together, these enable us to partition larger networks for co-simulation and parallel function evaluation.

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.
  • The CHANGELOG.md has been updated to reflect the changes. If this is a minor PR that is part of a larger fix already included in the file, state so.

@superwhiskers superwhiskers 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.

just an architectural question

Base automatically changed from abdou/clone to develop September 8, 2026 17:51
@nkoukpaizan
nkoukpaizan force-pushed the abdou/subsystem_model branch from 1ad85a7 to e23c7ba Compare September 8, 2026 17:51

@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.

A few specific comments.

This seems to work, but I find the logic of the BusPartitionInterface constructor and SubsystemModel index maps hard to follow. I would like to get inputs from @alexander-novo on those implementations.

I'll take another look after the initial comments have been addressed.

@abdourahmanbarry

abdourahmanbarry commented Sep 19, 2026 •

Copy link
Copy Markdown
Collaborator Author

@nkoukpaizan @alexander-novo @superwhiskers I have updated the code to incorporate the suggestions and improved the documentation to make the implementation easier to follow. Let me know what you think.

@superwhiskers superwhiskers 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.

just one minor comment

@abdourahmanbarry

Copy link
Copy Markdown
Collaborator Author

@nkoukpaizan I have added the partition interface that we discussed last time. It is simpler (and hopefully more efficient), but it only supports partitioning between a MicrogridBus and a MicrogridLine. I believe this covers the most common use cases for partitioning in cosim for PowerElectronics. I still advice we keep the other partition interface for partitioning test problems that are not necessarily PowerElectronics such as the Hires test problem.

CC: @pelesh @alexander-novo @superwhiskers

@superwhiskers superwhiskers 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.

looks good. all of these are nitpicks. SubsystemModelWithHires passes just fine on my machine.

@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 like the BusLinePartitionInterface. Please see my related comments and other comments below.

@read-the-docs-community

read-the-docs-community Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

@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.

A few minor comments. Good to merge after they are addressed.

Comment on lines +57 to +58
public:
using TimeFunction = std::function<void(ScalarT)>;

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 believe the argument should be RealT rather than ScalarT. Does the alias need to be public?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This is address in 60060e8

I left the alias as public as it is used by one of the methods as a parameter type. But it can be made private as well if that is preferable.

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.

Yes, let's keep it private.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Okay, sounds great.

@pelesh pelesh 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.

This looks good; there are only a few minor things to address before we merge:

Please address comments by @nkoukpaizan and a few comments here (mainly questions on implementation). If the code is intentionally implemented like this, please add comments explaining why. The implementation intent at places I flagged is not quite clear to me.

Comment on lines +720 to +723
/**
*@brief Maps global system connection indices to local subsystem connection indices.
*/
std::unordered_map<IdxT, IdxT> global_to_local_map_;

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.

Why use map here? Why not use vector with mapping indices?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The reason for using a map here is that the keys(global indices) belonging to a partition may not necessarily be contiguous. I am afraid using a vector could require create a large vector, even though only a small fraction of its entries would be used.

Comment on lines +29 to +30
~PartitionInterface() = default;
};

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 believe it should be:

Suggested change
~PartitionInterface() = default;
};
~PartitionInterface() override = default;
};

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This is addressed here 3b1ae4f

Comment on lines +695 to +701
for (component_type* comp : components_)
{
auto extern_indices = comp->getExternIndices();

for (IdxT j = 0; j < comp->size(); j++)
{
if (extern_indices.contains(j))

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.

Could we have instead:

Suggested change
for (component_type* comp : components_)
{
auto extern_indices = comp->getExternIndices();
for (IdxT j = 0; j < comp->size(); j++)
{
if (extern_indices.contains(j))
for (component_type* comp : components_)
{
const auto& extern_indices = comp->getExternIndices();
for (IdxT j = 0; j < comp->size(); j++)
{
if (extern_indices.contains(j))

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This is addressed here: 60060e8

Comment on lines +678 to +689
for (node_type* node : nodes_)
{
for (IdxT i = 0; i < node->size(); i++)
{
const IdxT global_connection = node->getNodeConnection(i).idx_;

if (global_connection != INVALID_INDEX<IdxT>)
{
global_to_local_map_[global_connection] = local_connection++;
}
}
}

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.

Here, in function buildConnectionMap(), i loops from 0 to node->size(). In allocate(), it loops from 0 to node->getInternalSize(). Why discrepancy?

@abdourahmanbarry abdourahmanbarry Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

These two are the same in this case. However, it is good to be consistent. Thank you.
This is addressed here: 60060e8

Comment on lines +193 to +201
// Map each node's global connection indices to subsystem-local indices,
// then set the corresponding state, derivative, and residual pointers.
for (node_type* node : nodes_)
{
for (IdxT i = 0; i < static_cast<IdxT>(node->getInternalSize()); i++)
{
const IdxT node_global_connection = node->getNodeConnection(i).idx_;
const IdxT node_local_connection = global_to_local_map_.at(node_global_connection);

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.

Her in allocate() function, i loops from 0 to node->getInternalSize(), whereas in buildConnectionMap(), an equivalent call loops from 0 to node->size(). Is this intended?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Like the previous comment, this has been addressed here: 60060e8

@pelesh

pelesh commented Nov 2, 2026

Copy link
Copy Markdown
Collaborator

One compiler warning to fix:

In file included from /Users/55y/src/gridkit/GridKit/tests/UnitTests/PowerElectronics/runPartitionPowerElectronicsTests.cpp:3:
/Users/55y/src/gridkit/GridKit/tests/UnitTests/PowerElectronics/PartitionPowerElectronicsTests.hpp:346:43: warning: implicit conversion changes signedness: 'int' to 'size_type' (aka 'unsigned long') [-Wsign-conversion]
  346 |             auto* partition = partitions_[p];
      |                               ~~~~~~~~~~~ ^
/Users/55y/src/gridkit/GridKit/tests/UnitTests/PowerElectronics/PartitionPowerElectronicsTests.hpp:88:43: note: in instantiation of member function 'GridKit::PowerElectronics::Testing::PartitionPowerElectronicsTests<double, unsigned long>::evaluatePartitions' requested here
   88 |           const auto partition_residual = evaluatePartitions(false);
      |                                           ^
/Users/55y/src/gridkit/GridKit/tests/UnitTests/PowerElectronics/runPartitionPowerElectronicsTests.cpp:11:18: note: in instantiation of member function 'GridKit::PowerElectronics::Testing::PartitionPowerElectronicsTests<double, unsigned long>::residual' requested here
   11 |   result += test.residual();
      |                  ^

The rest of the code compiles cleanly. All tests pass.


#pragma once

#include <omp.h>

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.

Suggested change
#include <omp.h>

This should not be needed and fails on my machine with GRIDKIT_ENABLE_OPENMP=Off

GridKit/tests/UnitTests/PowerElectronics/PartitionPowerElectronicsTests.hpp:4:10: fatal error: 'omp.h' file not found
    4 | #include <omp.h>
      |          ^~~~~~~

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

That's right. This is address in the following commits.

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants