-
Notifications
You must be signed in to change notification settings - Fork 10
Add Subsystem and Partition Interfaces for PowerElectronics #560
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
c0eddb4
Add BusPartitionInterface to define partition boundaries
abdourahmanbarry 6b607d4
Add SubsystemModel for partition evaluation
abdourahmanbarry b54e31d
Add HIRES test for SubsystemModel
abdourahmanbarry 81387dd
Add protected access to SystemModelPowerElectronics
abdourahmanbarry dc79452
Change external data vector to use GridKit vectors
abdourahmanbarry d10f40f
Updated SystemModelPowerElectronics.hpp
abdourahmanbarry c002f61
Update README.md for Hires problem
abdourahmanbarry f74f1f1
Minor update
abdourahmanbarry e23c7ba
Apply pre-commit fixes
abdourahmanbarry 8187314
Address leak in test
abdourahmanbarry File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
365 changes: 365 additions & 0 deletions
365
GridKit/Model/PowerElectronics/PartitionInterface/BusPartitionInterface.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,365 @@ | ||
|
|
||
| #include "BusPartitionInterface.hpp" | ||
|
|
||
| #include <cassert> | ||
| #include <cmath> | ||
| #include <cstddef> | ||
|
|
||
| #include <GridKit/Model/PowerElectronics/ExternalConnection.hpp> | ||
| #include <GridKit/Utilities/Logger/Logger.hpp> | ||
|
|
||
| namespace GridKit | ||
| { | ||
|
|
||
| /** | ||
| * @brief Construct a partition interface between a bus and a circuit component. | ||
| * | ||
| * The interface wraps a copy of a component located across a partition | ||
| * boundary and evaluates the contributions that the component makes to the | ||
| * connected bus. All interface variables are treated as external variables | ||
| * and have the same size as the wrapped component. | ||
| * | ||
| * | ||
| * @param bus Bus associated with the partition interface. | ||
| * @param component Copy of the component across the partition boundary. | ||
| * @param id Unique identifier for the interface. | ||
| */ | ||
| template <class ScalarT, typename IdxT> | ||
| BusPartitionInterface<ScalarT, IdxT>::BusPartitionInterface(node_type* bus, component_type* component, IdxT id) | ||
| : component_(component->clone()), | ||
| bus_(bus) | ||
| { | ||
| size_ = component_->size(); | ||
| n_intern_ = 0; | ||
| n_extern_ = static_cast<size_t>(component_->size()); | ||
| idc_ = id; | ||
|
|
||
| // All variables of the bus interface are external to the interface. | ||
| for (IdxT i = 0; i < size_; i++) | ||
| { | ||
| extern_indices_.insert(i); | ||
| } | ||
|
|
||
| // Map each global bus connection index to its position in the bus. | ||
| std::unordered_map<IdxT, size_t> bus_connections; | ||
|
|
||
| for (size_t i = 0; i < static_cast<size_t>(bus_->size()); ++i) | ||
| { | ||
| bus_connections[bus_->getNodeConnection(i).idx_] = i; | ||
| } | ||
|
|
||
| // The interface Jacobian contains only rows corresponding to variables | ||
| // owned by the bus. | ||
| const IdxT* coo_rows = component_->jacobianCooRows(); | ||
|
|
||
| nnz_ = 0; | ||
|
|
||
| for (IdxT k = 0; k < component_->nnz(); ++k) | ||
| { | ||
| const IdxT row_node = component_->getNodeConnection(static_cast<size_t>(coo_rows[k])); | ||
|
|
||
| if (bus_connections.contains(row_node)) | ||
| { | ||
| ++nnz_; | ||
| jac_map_.push_back(k); // Keep track of the entries so they can be easily extracted | ||
| } | ||
| } | ||
| } | ||
|
|
||
| template <class ScalarT, typename IdxT> | ||
| BusPartitionInterface<ScalarT, IdxT>::~BusPartitionInterface() | ||
| { | ||
| delete component_; | ||
| } | ||
|
|
||
| /** | ||
| * @brief Allocate storage and initialize the interface mappings. | ||
| * | ||
| * Identifies the external variables of the wrapped component that are | ||
| * connected to the bus and builds the mappings used to transfer residual | ||
| * contributions between the component and the interface. Private storage is | ||
| * also allocated for the internal variables of the wrapped component. | ||
| * | ||
| * @return 0 on success and a nonzero value if the component does not contain | ||
| * all variables required by the bus interface. | ||
| */ | ||
| template <class ScalarT, typename IdxT> | ||
| int BusPartitionInterface<ScalarT, IdxT>::allocate() | ||
| { | ||
|
|
||
| CircuitComponent<ScalarT, IdxT>::allocate(); | ||
|
|
||
| // Build a lookup of the global indices belonging to the bus. | ||
| std::unordered_map<IdxT, size_t> bus_connections; | ||
|
|
||
| for (size_t i = 0; i < static_cast<size_t>(bus_->size()); ++i) | ||
| { | ||
| bus_connections[bus_->getNodeConnection(i).idx_] = i; | ||
| } | ||
|
|
||
| const auto& external_indices = component_->getExternIndices(); | ||
|
|
||
| is_external_.assign(static_cast<size_t>(size_), false); | ||
|
|
||
| bus_input_ports_.clear(); | ||
| bus_output_ports_.clear(); | ||
|
|
||
| size_t external_index = 0; | ||
|
|
||
| // Identify which component variables are external and which of those external | ||
| // variables are connected to the bus. bus_input_ports_ stores the corresponding | ||
| // variable position in this interface, while bus_output_ports_ stores its position | ||
| // in the wrapped component's external residual vector. | ||
| for (size_t i = 0; i < static_cast<size_t>(size_); ++i) | ||
| { | ||
| const IdxT connection_index = component_->getNodeConnection(i); | ||
|
|
||
| this->setConnectionNodes(i, connection_index); | ||
|
|
||
| if (!external_indices.contains(static_cast<IdxT>(i))) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| is_external_[i] = true; | ||
|
|
||
| if (bus_connections.contains(connection_index)) | ||
| { | ||
| bus_input_ports_.push_back(i); | ||
| bus_output_ports_.push_back(external_index); | ||
| } | ||
|
|
||
| ++external_index; | ||
| } | ||
|
|
||
| // A valid bus interface must contain every variable belonging to the bus. | ||
| // If fewer bus variables are found, the wrapped component does not provide | ||
| // the complete coupling required by this interface. | ||
| const size_t bus_size = static_cast<size_t>(bus_->size()); | ||
|
|
||
| if (bus_input_ports_.size() != bus_size) | ||
| { | ||
| GridKit::Utilities::Logger::error() << "ERROR: Invalid partition interface detected. " | ||
| << "Bus(ID=" << bus_->busID() | ||
| << "), Component(ID=" << component_->getIDcomponent() | ||
| << "). Expected " << bus_size | ||
| << " bus connections, but found " | ||
| << bus_input_ports_.size() << "." | ||
| << std::endl; | ||
|
|
||
| return 1; | ||
| } | ||
|
|
||
| // The wrapped component is evaluated independently by the interface. | ||
| // Allocate storage for its internal variables and residuals and redirect | ||
| // its internal pointers to this private storage. | ||
| const size_t internal_size = static_cast<size_t>(component_->getInternalSize()); | ||
|
|
||
| component_y_int_ = std::make_unique<ScalarT[]>(internal_size); | ||
| component_yp_int_ = std::make_unique<ScalarT[]>(internal_size); | ||
| component_f_int_ = std::make_unique<ScalarT[]>(internal_size); | ||
|
|
||
| component_->setInternalPointer(component_y_int_.get()); | ||
| component_->setInternalDerivativePointer(component_yp_int_.get()); | ||
| component_->setInternalResidualPointer(component_f_int_.get()); | ||
|
|
||
| component_f_ext_ = std::make_unique<ScalarT[]>(component_->getExternSize()); | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| template <class ScalarT, typename IdxT> | ||
| int BusPartitionInterface<ScalarT, IdxT>::setAbsoluteTolerance(RealT rel_tol) | ||
| { | ||
| abs_tol_.setToConst(static_cast<ScalarT>(rel_tol)); | ||
| return 0; | ||
| } | ||
|
|
||
| /** | ||
| * @brief Initialize the partition interface. | ||
| * | ||
| * @return 0 on success. | ||
| */ | ||
| template <class ScalarT, typename IdxT> | ||
| int BusPartitionInterface<ScalarT, IdxT>::initialize() | ||
| { | ||
| return 0; | ||
| } | ||
|
|
||
| /** | ||
| * @brief Identify differential variables | ||
| */ | ||
| template <class ScalarT, typename IdxT> | ||
| int BusPartitionInterface<ScalarT, IdxT>::tagDifferentiable() | ||
| { | ||
| return 0; | ||
| } | ||
|
|
||
| /** | ||
| * @brief Eval Internal Residual | ||
| */ | ||
| template <class ScalarT, typename IdxT> | ||
| int BusPartitionInterface<ScalarT, IdxT>::evaluateInternalResidual() | ||
| { | ||
| return 0; | ||
| } | ||
|
Comment on lines
+198
to
+205
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add the relevant comment from the class documentation ("all variables are external from the interface's point of view") here to explain why this is no-op. |
||
|
|
||
| /** | ||
| * @brief Evaluate the wrapped component's contributions to the bus residual. | ||
| * | ||
| * The wrapped component is evaluated using state information supplied through | ||
| * the interface. Residual contributions associated with bus variables are | ||
| * extracted from the component's external residual and accumulated into the | ||
| * corresponding interface residual entries. | ||
| * | ||
| * @return 0 on success, or the error code returned by the wrapped component. | ||
| */ | ||
| template <class ScalarT, typename IdxT> | ||
| int BusPartitionInterface<ScalarT, IdxT>::evaluateExternalResidual() | ||
| { | ||
| std::fill_n(component_f_ext_.get(), component_->getExternSize(), ScalarT{}); | ||
|
|
||
| updateComponentPointers(); | ||
|
|
||
| if (int err_code = component_->evaluateExternalResidual()) | ||
| { | ||
| return err_code; | ||
| } | ||
|
|
||
| // Only contributions associated with the bus are accumulated | ||
| // into the interface residual below. | ||
| for (size_t i = 0; i < bus_input_ports_.size(); ++i) | ||
| { | ||
| *f_ext_[bus_input_ports_[i]] += component_f_ext_[bus_output_ports_[i]]; | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| /** | ||
| * @brief Evaluate the Jacobian contributions associated with the bus. | ||
| * | ||
| * Evaluates the Jacobian of the wrapped component and extracts the entries | ||
| * whose residual rows correspond to variables belonging to the connected bus. | ||
| * The selected entries are then used to assemble the interface Jacobian. | ||
| * | ||
| * @return 0 on success. | ||
| */ | ||
| template <class ScalarT, typename IdxT> | ||
| int BusPartitionInterface<ScalarT, IdxT>::evaluateJacobian() | ||
| { | ||
|
|
||
| this->zeroJacMatrix(); | ||
|
|
||
| updateComponentPointers(); | ||
|
|
||
| component_->evaluateJacobian(); | ||
|
|
||
| const IdxT* cooRows = component_->jacobianCooRows(); | ||
| const IdxT* cooCols = component_->jacobianCooCols(); | ||
| const RealT* cooVals = component_->jacobianCooValues(); | ||
|
|
||
| std::vector<IdxT> rows; | ||
| std::vector<IdxT> cols; | ||
| std::vector<RealT> vals; | ||
|
|
||
| rows.reserve(jac_map_.size()); | ||
| cols.reserve(jac_map_.size()); | ||
| vals.reserve(jac_map_.size()); | ||
|
|
||
| // Extract only the Jacobian entries whose residual rows belong to the bus. | ||
| for (const IdxT index : jac_map_) | ||
| { | ||
| rows.push_back(cooRows[index]); | ||
| cols.push_back(cooCols[index]); | ||
| vals.push_back(cooVals[index]); | ||
| } | ||
|
|
||
| this->setJacValues(rows, cols, vals); | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| /** | ||
| * @brief Update the wrapped component with state and output residual pointers. | ||
| * | ||
| * Reconstructs the state required to evaluate the wrapped component using | ||
| * data supplied through the interface. External component variables are | ||
| * connected directly to the interface data, while internal component | ||
| * variables are copied into the interface's private storage, which the wrapped | ||
| * component already keeps track of for its internal state. | ||
| * | ||
| * @pre The interface must be allocated and its external state pointers must | ||
| * reference valid state and derivative data. | ||
| * | ||
| * @post The wrapped component is configured with the state, derivative, and | ||
| * residual pointers required for evaluation. | ||
| * | ||
| * @param residual Storage for the component's external residual contributions, | ||
| * or nullptr when residual output is not required. | ||
| * | ||
| * @return 0 on success. | ||
| */ | ||
| template <class ScalarT, typename IdxT> | ||
| int BusPartitionInterface<ScalarT, IdxT>::updateComponentPointers() | ||
| { | ||
| size_t internal_index = 0; | ||
| size_t external_index = 0; | ||
|
|
||
| // Reconstruct the state expected by the wrapped component from the | ||
| // interface's external data. Route the external residual to component_f_ext_. | ||
| for (size_t i = 0; i < static_cast<size_t>(component_->size()); ++i) | ||
| { | ||
| if (is_external_[i]) | ||
| { | ||
| ExternalConnection<ScalarT, IdxT> connection{ | ||
| .y_ = y_ext_[i], | ||
| .yp_ = yp_ext_[i], | ||
| .f_ = &component_f_ext_[external_index], | ||
| .idx_ = component_->getNodeConnection(i)}; | ||
|
|
||
| component_->setExternalConnectionNodes(i, connection); | ||
| ++external_index; | ||
| } | ||
| else | ||
| { | ||
| component_y_int_[internal_index] = *y_ext_[i]; | ||
| component_yp_int_[internal_index] = *yp_ext_[i]; | ||
| ++internal_index; | ||
| } | ||
| } | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| template <class ScalarT, typename IdxT> | ||
| int BusPartitionInterface<ScalarT, IdxT>::evaluateIntegrand() | ||
| { | ||
| return 0; | ||
| } | ||
|
|
||
| template <class ScalarT, typename IdxT> | ||
| int BusPartitionInterface<ScalarT, IdxT>::initializeAdjoint() | ||
| { | ||
| return 0; | ||
| } | ||
|
|
||
| template <class ScalarT, typename IdxT> | ||
| int BusPartitionInterface<ScalarT, IdxT>::evaluateAdjointResidual() | ||
| { | ||
| return 0; | ||
| } | ||
|
|
||
| template <class ScalarT, typename IdxT> | ||
| int BusPartitionInterface<ScalarT, IdxT>::evaluateAdjointIntegrand() | ||
| { | ||
| return 0; | ||
| } | ||
|
|
||
| // Available template instantiations | ||
| template class BusPartitionInterface<double, long int>; | ||
| template class BusPartitionInterface<double, size_t>; | ||
| template class BusPartitionInterface<DependencyTracking::Variable, long int>; | ||
| template class BusPartitionInterface<DependencyTracking::Variable, size_t>; | ||
|
|
||
| } // namespace GridKit | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I usually avoid the
continuepattern and prefer checking the opposite condtion.