Initial Implementation of Subsystem Model for Partition Simulation - #492
Initial Implementation of Subsystem Model for Partition Simulation#492abdourahmanbarry wants to merge 53 commits into
Conversation
85a516d to
01a410b
Compare
66c58ad to
b48a401
Compare
a375b1f to
f65baeb
Compare
|
This pull request is ready for review. |
e96184a to
98be2e0
Compare
…es. During partitioning: - BusPartitionInterface connects to the bus partition - ComponentPartitionInterface connects to the component partition
…ample more rebust
- 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.
98be2e0 to
f082543
Compare
nkoukpaizan
left a comment
There was a problem hiding this comment.
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.
- 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
left a comment
There was a problem hiding this comment.
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.mduntil it's closer to ready to merge to reduce the need to rebase. - We need to better document how
clone()andforcing_datawork 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
| auto isEqual = [&tolerance](RealT value, RealT reference) | ||
| { | ||
| if (tolerance) | ||
| { | ||
| return GridKit::Testing::isEqual(value, reference, *tolerance); | ||
| } | ||
|
|
||
| return GridKit::Testing::isEqual(value, reference); | ||
| }; |
There was a problem hiding this comment.
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 | |||
There was a problem hiding this comment.
This is a welcome change! Consider isolating this into a quick PR to facilitate review and narrow the scope of this one.
| 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) |
There was a problem hiding this comment.
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] |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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/.
| 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_); |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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!
| if (!is_internal_entry) | ||
| { | ||
| vals[map_to_csr_[counter]] += v[i]; | ||
| ++counter; | ||
| continue; | ||
| } | ||
|
|
||
| vals[map_to_csr_[counter]] += v[i]; | ||
| ++counter; |
There was a problem hiding this comment.
This is clearer to me. Multiple instances of this.
| 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> |
There was a problem hiding this comment.
Please add a todo to make the names more intuitive, potentially renaming the base class.
| /** | ||
| *@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_; |
There was a problem hiding this comment.
Can't we use the same storage types as the base classes, e.g., GridKit::LinearAlgebra::Vector?
Description
In this PR, we introduce the initial implementation of the
SubsystemModelfor 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
SubsystemModelclass to represent an individual partition and aBusPartitionInterfacecomponent to mark partition boundaries.Checklist
-Wall -Wpedantic -Wconversion -Wextra.