diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e3336671..ea51a9bb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -83,6 +83,7 @@ - Added cases and validation for ACTIVSg10k, ACTIVSg200, ACTIVSg500, and WECC240. - Added IDA option to choose the consistent initial condition calculation type. - Implemented `tagDifferentiable()` for `PowerElectronics` models. +- Fixed the `TenGenGenrou` example to output the correct omega values. ## v0.1 diff --git a/GridKit/Model/PowerElectronics/Capacitor/Capacitor.cpp b/GridKit/Model/PowerElectronics/Capacitor/Capacitor.cpp index 6c0b5fdf6..4381abc55 100644 --- a/GridKit/Model/PowerElectronics/Capacitor/Capacitor.cpp +++ b/GridKit/Model/PowerElectronics/Capacitor/Capacitor.cpp @@ -54,6 +54,25 @@ 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. + */ + template + int Capacitor::setAbsoluteTolerance(RealT rel_tol) + { + abs_tol_.setToConst(static_cast(rel_tol)); + return 0; + } + /** * @brief Evaluate the resisdual of the Capcitor * @@ -119,6 +138,18 @@ namespace GridKit return 0; } + template + bool Capacitor::isCloneable() const + { + return true; + } + + template + CircuitComponent* Capacitor::clone() const + { + return new Capacitor(*this); + } + // Available template instantiations template class Capacitor; template class Capacitor; diff --git a/GridKit/Model/PowerElectronics/Capacitor/Capacitor.hpp b/GridKit/Model/PowerElectronics/Capacitor/Capacitor.hpp index d7a131a9a..0b3353c47 100644 --- a/GridKit/Model/PowerElectronics/Capacitor/Capacitor.hpp +++ b/GridKit/Model/PowerElectronics/Capacitor/Capacitor.hpp @@ -29,6 +29,7 @@ namespace GridKit using CircuitComponent::y_int_; using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; + using CircuitComponent::abs_tol_; using CircuitComponent::tag_; using CircuitComponent::f_ext_; using CircuitComponent::f_int_; @@ -50,15 +51,19 @@ namespace GridKit int initialize(); int tagDifferentiable(); + int setAbsoluteTolerance(RealT); int evaluateInternalResidual() final; int evaluateExternalResidual() final; int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT C_; diff --git a/GridKit/Model/PowerElectronics/CircuitComponent.hpp b/GridKit/Model/PowerElectronics/CircuitComponent.hpp index a033b46e7..f3a0a8d09 100644 --- a/GridKit/Model/PowerElectronics/CircuitComponent.hpp +++ b/GridKit/Model/PowerElectronics/CircuitComponent.hpp @@ -27,6 +27,138 @@ 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); + destination.copyFromExternal(source); + }; + + /* + * Deep-copy the local-to-global connection mapping. + */ + if (other.connection_nodes_) + { + connection_nodes_ = std::make_unique(static_cast(size_)); + + for (size_t i = 0; i < static_cast(size_); ++i) + { + connection_nodes_[i] = other.connection_nodes_[i]; + } + } + + /* + * Deep-copy the COO Jacobian row indices. + */ + if (other.jacobian_coo_rows_) + { + jacobian_coo_rows_ = std::make_unique(static_cast(nnz_)); + + for (size_t i = 0; i < static_cast(nnz_); ++i) + { + jacobian_coo_rows_[i] = other.jacobian_coo_rows_[i]; + } + } + + /* + * Deep-copy the COO Jacobian column indices. + */ + if (other.jacobian_coo_cols_) + { + jacobian_coo_cols_ = std::make_unique(static_cast(nnz_)); + + for (size_t i = 0; i < static_cast(nnz_); ++i) + { + jacobian_coo_cols_[i] = other.jacobian_coo_cols_[i]; + } + } + + /* + * Deep-copy the COO Jacobian values. + */ + if (other.jacobian_coo_values_) + { + jacobian_coo_values_ = std::make_unique(static_cast(nnz_)); + + for (size_t i = 0; i < static_cast(nnz_); ++i) + { + jacobian_coo_values_[i] = other.jacobian_coo_values_[i]; + } + } + + if (size_ > 0) + { + y_ext_ = std::make_unique(static_cast(size_)); + yp_ext_ = std::make_unique(static_cast(size_)); + f_ext_ = std::make_unique(static_cast(size_)); + + for (size_t i = 0; i < static_cast(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_); + } + + virtual CircuitComponent* clone() const + { + return nullptr; + } + + virtual bool isCloneable() const + { + return false; + } + /** * @note Cannot be marked final, since it is overriden to recurse in the system model. */ @@ -51,7 +183,7 @@ namespace GridKit return this->n_intern_; } - std::set getExternIndices() + std::set getExternIndices() { return this->extern_indices_; } @@ -69,7 +201,7 @@ namespace GridKit int setInternalConnectionNodes(size_t local_index, IdxT global_index) { assert(!extern_indices_.contains(static_cast(local_index))); - connection_nodes_[local_index] = global_index; + setConnectionNodes(local_index, global_index); return 0; } @@ -88,10 +220,27 @@ namespace GridKit int setExternalConnectionNodes(size_t local_index, ExternalConnection connection) { assert(extern_indices_.contains(local_index)); - y_ext_[local_index] = connection.y_; - yp_ext_[local_index] = connection.yp_; - f_ext_[local_index] = connection.f_; - connection_nodes_[local_index] = connection.idx_; + y_ext_[local_index] = connection.y_; + yp_ext_[local_index] = connection.yp_; + f_ext_[local_index] = connection.f_; + setConnectionNodes(local_index, connection.idx_); + return 0; + } + + /** + * @brief Update the connection index for a variable. + * + * Sets only the connection index without modifying the variable's + * internal/external classification or its associated data pointers. + * + * @param local_index Index of the local variable. + * @param connection_index New connection index for the variable. + * + * @return int 0 if successful. + */ + int setConnectionNodes(size_t local_index, IdxT connection_index) + { + connection_nodes_[local_index] = connection_index; return 0; } @@ -132,9 +281,10 @@ namespace GridKit jacobian_coo_cols_ = std::make_unique(static_cast(nnz_)); jacobian_coo_values_ = std::make_unique(static_cast(nnz_)); - y_ext_ = std::make_unique(static_cast(size_)); - yp_ext_ = std::make_unique(static_cast(size_)); - f_ext_ = std::make_unique(static_cast(size_)); + y_ext_ = std::make_unique(static_cast(size_)); + yp_ext_ = std::make_unique(static_cast(size_)); + f_ext_ = std::make_unique(static_cast(size_)); + connection_nodes_ = std::make_unique(static_cast(size_)); tag_.resize(static_cast(size_)); @@ -441,6 +591,16 @@ namespace GridKit return idc_; } + /** + * @brief Check whether the component has already been allocated. + * + * @return true if allocate() has previously completed, false otherwise. + */ + bool isAllocated() const + { + return allocated_; + } + protected: /** * @brief Allocate state and residual storage owned by this component. diff --git a/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.cpp b/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.cpp index aa538933f..1cc86e989 100644 --- a/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.cpp +++ b/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.cpp @@ -422,6 +422,18 @@ namespace GridKit return 0; } + template + bool DistributedGenerator::isCloneable() const + { + return true; + } + + template + CircuitComponent* DistributedGenerator::clone() const + { + return new DistributedGenerator(*this); + } + // Available template instantiations template class DistributedGenerator; template class DistributedGenerator; diff --git a/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.hpp b/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.hpp index ab7e340f1..8a5219848 100644 --- a/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.hpp +++ b/GridKit/Model/PowerElectronics/DistributedGenerator/DistributedGenerator.hpp @@ -75,18 +75,21 @@ namespace GridKit NodeT* node_bus); virtual ~DistributedGenerator(); - int initialize(); - int allocate() final; - int tagDifferentiable(); - int setAbsoluteTolerance(RealT); - int evaluateInternalResidual() final; - int evaluateExternalResidual() final; - int evaluateJacobian(); - int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initialize(); + int allocate() final; + int tagDifferentiable(); + int setAbsoluteTolerance(RealT); + int evaluateInternalResidual() final; + int evaluateExternalResidual() final; + int evaluateJacobian(); + int evaluateIntegrand(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT wb_; diff --git a/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.cpp b/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.cpp index 74aabb549..d15913e72 100644 --- a/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.cpp +++ b/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.cpp @@ -65,6 +65,25 @@ 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. + */ + template + int InductionMotor::setAbsoluteTolerance(RealT rel_tol) + { + abs_tol_.setToConst(static_cast(rel_tol)); + return 0; + } + /** * @brief Contributes to the resisdual * @@ -131,6 +150,18 @@ namespace GridKit return 0; } + template + bool InductionMotor::isCloneable() const + { + return true; + } + + template + CircuitComponent* InductionMotor::clone() const + { + return new InductionMotor(*this); + } + // Available template instantiations template class InductionMotor; template class InductionMotor; diff --git a/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.hpp b/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.hpp index 122cd4d30..6f1724670 100644 --- a/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.hpp +++ b/GridKit/Model/PowerElectronics/InductionMotor/InductionMotor.hpp @@ -29,6 +29,7 @@ namespace GridKit using CircuitComponent::y_int_; using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; + using CircuitComponent::abs_tol_; using CircuitComponent::tag_; using CircuitComponent::f_ext_; using CircuitComponent::f_int_; @@ -50,15 +51,19 @@ namespace GridKit int initialize(); int tagDifferentiable(); + int setAbsoluteTolerance(RealT); int evaluateInternalResidual() final; int evaluateExternalResidual() final; int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT Lls_; diff --git a/GridKit/Model/PowerElectronics/Inductor/Inductor.cpp b/GridKit/Model/PowerElectronics/Inductor/Inductor.cpp index 0e6e7ea28..6e9969366 100644 --- a/GridKit/Model/PowerElectronics/Inductor/Inductor.cpp +++ b/GridKit/Model/PowerElectronics/Inductor/Inductor.cpp @@ -149,6 +149,18 @@ namespace GridKit return 0; } + template + bool Inductor::isCloneable() const + { + return true; + } + + template + CircuitComponent* Inductor::clone() const + { + return new Inductor(*this); + } + // Available template instantiations template class Inductor; template class Inductor; diff --git a/GridKit/Model/PowerElectronics/Inductor/Inductor.hpp b/GridKit/Model/PowerElectronics/Inductor/Inductor.hpp index b82ce1070..30d25db79 100644 --- a/GridKit/Model/PowerElectronics/Inductor/Inductor.hpp +++ b/GridKit/Model/PowerElectronics/Inductor/Inductor.hpp @@ -60,10 +60,13 @@ namespace GridKit int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT L_; diff --git a/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.cpp b/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.cpp index 455ef202f..864250abc 100644 --- a/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.cpp +++ b/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.cpp @@ -67,6 +67,25 @@ 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. + */ + template + int LinearTransformer::setAbsoluteTolerance(RealT rel_tol) + { + abs_tol_.setToConst(static_cast(rel_tol)); + return 0; + } + /** * @brief Computes the component resisdual */ @@ -116,6 +135,18 @@ namespace GridKit return 0; } + template + bool LinearTransformer::isCloneable() const + { + return true; + } + + template + CircuitComponent* LinearTransformer::clone() const + { + return new LinearTransformer(*this); + } + // Available template instantiations template class LinearTransformer; template class LinearTransformer; diff --git a/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.hpp b/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.hpp index 62dc84305..6b75dcc1d 100644 --- a/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.hpp +++ b/GridKit/Model/PowerElectronics/LinearTransformer/LinearTransformer.hpp @@ -29,6 +29,7 @@ namespace GridKit using CircuitComponent::y_int_; using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; + using CircuitComponent::abs_tol_; using CircuitComponent::tag_; using CircuitComponent::f_ext_; using CircuitComponent::f_int_; @@ -50,15 +51,19 @@ namespace GridKit int initialize(); int tagDifferentiable(); + int setAbsoluteTolerance(RealT); int evaluateInternalResidual() final; int evaluateExternalResidual() final; int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT L0_; diff --git a/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.cpp b/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.cpp index 462c200f8..1fee11c4b 100644 --- a/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.cpp +++ b/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.cpp @@ -152,6 +152,18 @@ namespace GridKit return 0; } + template + bool MicrogridBusDQ::isCloneable() const + { + return true; + } + + template + CircuitComponent* MicrogridBusDQ::clone() const + { + return new MicrogridBusDQ(*this); + } + // Available template instantiations template class MicrogridBusDQ; template class MicrogridBusDQ; diff --git a/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.hpp b/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.hpp index 111ca7be8..2314700a3 100644 --- a/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.hpp +++ b/GridKit/Model/PowerElectronics/MicrogridBusDQ/MicrogridBusDQ.hpp @@ -60,10 +60,13 @@ namespace GridKit int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT RN_; diff --git a/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.cpp b/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.cpp index efa5c2a36..7e5f993c4 100644 --- a/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.cpp +++ b/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.cpp @@ -184,6 +184,18 @@ namespace GridKit return 0; } + template + bool MicrogridLine::isCloneable() const + { + return true; + } + + template + CircuitComponent* MicrogridLine::clone() const + { + return new MicrogridLine(*this); + } + // Available template instantiations template class MicrogridLine; template class MicrogridLine; diff --git a/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.hpp b/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.hpp index 1354a9d9b..041562cbb 100644 --- a/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.hpp +++ b/GridKit/Model/PowerElectronics/MicrogridLine/MicrogridLine.hpp @@ -60,10 +60,13 @@ namespace GridKit int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT R_; diff --git a/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.cpp b/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.cpp index 36ac6c375..9e6098d0f 100644 --- a/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.cpp +++ b/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.cpp @@ -175,6 +175,18 @@ namespace GridKit return 0; } + template + bool MicrogridLoad::isCloneable() const + { + return true; + } + + template + CircuitComponent* MicrogridLoad::clone() const + { + return new MicrogridLoad(*this); + } + // Available template instantiations template class MicrogridLoad; template class MicrogridLoad; diff --git a/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.hpp b/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.hpp index 931983d50..6189e941c 100644 --- a/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.hpp +++ b/GridKit/Model/PowerElectronics/MicrogridLoad/MicrogridLoad.hpp @@ -60,10 +60,13 @@ namespace GridKit int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT R_; diff --git a/GridKit/Model/PowerElectronics/NodeBase.hpp b/GridKit/Model/PowerElectronics/NodeBase.hpp index 077854b97..b39539781 100644 --- a/GridKit/Model/PowerElectronics/NodeBase.hpp +++ b/GridKit/Model/PowerElectronics/NodeBase.hpp @@ -136,6 +136,23 @@ namespace GridKit }; } + /** + * @brief Update the connection index for a variable. + * + * Changes only the connection index without modifying the variable's + * internal/external classification or its associated data pointers. + * + * @param local_index Index of the local variable. + * @param connection_index New connection index for the variable. + * + * @return int 0 if successful. + */ + int setConnectionNodes(size_t local_index, IdxT connection_index) + { + connection_nodes_[local_index] = connection_index; + return 0; + } + int allocate() override { size_t size = static_cast(n_intern_ + n_extern_); @@ -392,6 +409,16 @@ namespace GridKit return gB_; } + /** + * @brief Check whether the Node has already been allocated. + * + * @return true if allocate() has previously completed, false otherwise. + */ + bool isAllocated() const + { + return allocated_; + } + private: void allocateVectors(IdxT n) { diff --git a/GridKit/Model/PowerElectronics/Resistor/Resistor.cpp b/GridKit/Model/PowerElectronics/Resistor/Resistor.cpp index 8fba09a55..55caa4837 100644 --- a/GridKit/Model/PowerElectronics/Resistor/Resistor.cpp +++ b/GridKit/Model/PowerElectronics/Resistor/Resistor.cpp @@ -139,6 +139,18 @@ namespace GridKit return 0; } + template + bool Resistor::isCloneable() const + { + return true; + } + + template + CircuitComponent* Resistor::clone() const + { + return new Resistor(*this); + } + // Available template instantiations template class Resistor; template class Resistor; diff --git a/GridKit/Model/PowerElectronics/Resistor/Resistor.hpp b/GridKit/Model/PowerElectronics/Resistor/Resistor.hpp index 540ab4d20..19c90a190 100644 --- a/GridKit/Model/PowerElectronics/Resistor/Resistor.hpp +++ b/GridKit/Model/PowerElectronics/Resistor/Resistor.hpp @@ -60,10 +60,13 @@ namespace GridKit int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT R_; diff --git a/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.cpp b/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.cpp index 5ec5b3b91..408bf241c 100644 --- a/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.cpp +++ b/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.cpp @@ -82,6 +82,25 @@ 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. + */ + template + int SynchronousMachine::setAbsoluteTolerance(RealT rel_tol) + { + abs_tol_.setToConst(static_cast(rel_tol)); + return 0; + } + /** * @brief Compute the resisdual of the component. * @@ -165,6 +184,18 @@ namespace GridKit return 0; } + template + bool SynchronousMachine::isCloneable() const + { + return true; + } + + template + CircuitComponent* SynchronousMachine::clone() const + { + return new SynchronousMachine(*this); + } + // Available template instantiations template class SynchronousMachine; template class SynchronousMachine; diff --git a/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.hpp b/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.hpp index 80b68eed2..7cf040583 100644 --- a/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.hpp +++ b/GridKit/Model/PowerElectronics/SynchronousMachine/SynchronousMachine.hpp @@ -31,6 +31,7 @@ namespace GridKit using CircuitComponent::y_int_; using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; + using CircuitComponent::abs_tol_; using CircuitComponent::tag_; using CircuitComponent::f_ext_; using CircuitComponent::f_int_; @@ -52,15 +53,19 @@ namespace GridKit int initialize(); int tagDifferentiable(); + int setAbsoluteTolerance(RealT); int evaluateInternalResidual() final; int evaluateExternalResidual() final; int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT Lls_; diff --git a/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.cpp b/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.cpp index f4700e275..cfefa499f 100644 --- a/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.cpp +++ b/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.cpp @@ -65,6 +65,25 @@ 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. + */ + template + int TransmissionLine::setAbsoluteTolerance(RealT rel_tol) + { + abs_tol_.setToConst(static_cast(rel_tol)); + return 0; + } + /** * @brief Evaluate residual of transmission line * @@ -186,6 +205,18 @@ namespace GridKit return 0; } + template + bool TransmissionLine::isCloneable() const + { + return true; + } + + template + CircuitComponent* TransmissionLine::clone() const + { + return new TransmissionLine(*this); + } + // Available template instantiations template class TransmissionLine; template class TransmissionLine; diff --git a/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.hpp b/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.hpp index 091984c89..c9743e9dd 100644 --- a/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.hpp +++ b/GridKit/Model/PowerElectronics/TransmissionLine/TransmissionLine.hpp @@ -33,6 +33,7 @@ namespace GridKit using CircuitComponent::y_int_; using CircuitComponent::yp_ext_; using CircuitComponent::yp_int_; + using CircuitComponent::abs_tol_; using CircuitComponent::tag_; using CircuitComponent::f_ext_; using CircuitComponent::f_int_; @@ -54,15 +55,19 @@ namespace GridKit int initialize(); int tagDifferentiable(); + int setAbsoluteTolerance(RealT); int evaluateInternalResidual() final; int evaluateExternalResidual() final; int evaluateJacobian(); int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT R_; diff --git a/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.cpp b/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.cpp index 52f021a5a..3ac673129 100644 --- a/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.cpp +++ b/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.cpp @@ -142,6 +142,18 @@ namespace GridKit return 0; } + template + bool VoltageSource::isCloneable() const + { + return true; + } + + template + CircuitComponent* VoltageSource::clone() const + { + return new VoltageSource(*this); + } + // Available template instantiations template class VoltageSource; template class VoltageSource; diff --git a/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.hpp b/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.hpp index 814fa5ec5..ab9125f40 100644 --- a/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.hpp +++ b/GridKit/Model/PowerElectronics/VoltageSource/VoltageSource.hpp @@ -60,10 +60,13 @@ namespace GridKit int evaluateJacobian() final; int evaluateIntegrand(); - int initializeAdjoint(); - int evaluateAdjointResidual(); + int initializeAdjoint(); + int evaluateAdjointResidual(); // int evaluateAdjointJacobian(); - int evaluateAdjointIntegrand(); + int evaluateAdjointIntegrand(); + bool isCloneable() const; + + CircuitComponent* clone() const; private: RealT V_; diff --git a/examples/PhasorDynamics/Small/TenGen/Genrou/TenGenGenrou.cpp b/examples/PhasorDynamics/Small/TenGen/Genrou/TenGenGenrou.cpp index 402f554be..b140eddc0 100644 --- a/examples/PhasorDynamics/Small/TenGen/Genrou/TenGenGenrou.cpp +++ b/examples/PhasorDynamics/Small/TenGen/Genrou/TenGenGenrou.cpp @@ -135,9 +135,8 @@ int main() for (size_t i = 0; i < 9; ++i) { // 18 is offset for variables of 9 buses. - // Each generator has 21 equations. // We are outputting second equation of each generator. - out << yval[18 + 21 * i + 1] << ","; + out << yval[18 + gen2.size() * i + 1] << ","; } out << "\n"; }; diff --git a/examples/PowerElectronics/CMakeLists.txt b/examples/PowerElectronics/CMakeLists.txt index 2bf311e22..920e63e46 100644 --- a/examples/PowerElectronics/CMakeLists.txt +++ b/examples/PowerElectronics/CMakeLists.txt @@ -3,6 +3,7 @@ # - Slaven Peles #]] +add_subdirectory(PowerElectronicsExamplesHelper) add_subdirectory(DistributedGeneratorTest) if(TARGET SUNDIALS::idas) diff --git a/examples/PowerElectronics/Microgrid/CMakeLists.txt b/examples/PowerElectronics/Microgrid/CMakeLists.txt index 6eae26be3..a919cd9cc 100644 --- a/examples/PowerElectronics/Microgrid/CMakeLists.txt +++ b/examples/PowerElectronics/Microgrid/CMakeLists.txt @@ -1,11 +1,13 @@ add_executable(microgrid Microgrid.cpp) + target_link_libraries( microgrid GridKit::power_elec_disgen GridKit::power_elec_microline GridKit::power_elec_microload GridKit::solvers_dyn - GridKit::power_elec_microbusdq) + GridKit::power_elec_microbusdq + GridKit::power_elec_microgrid_network) add_test(NAME Microgrid COMMAND $) install(TARGETS microgrid RUNTIME DESTINATION bin) diff --git a/examples/PowerElectronics/Microgrid/Microgrid.cpp b/examples/PowerElectronics/Microgrid/Microgrid.cpp index dfd71a7e1..cf828bf2d 100644 --- a/examples/PowerElectronics/Microgrid/Microgrid.cpp +++ b/examples/PowerElectronics/Microgrid/Microgrid.cpp @@ -1,21 +1,13 @@ #include -#include -#include -#include +#include #include -#include -#include - -#include -#include -#include -#include -#include -#include + #include #include #include +#include + int main(int /* argc */, char const** /* argv */) { /// @todo Needs to be modified. Some components are small relative to others thus @@ -28,139 +20,14 @@ int main(int /* argc */, char const** /* argv */) // Create model auto* sysmodel = new GridKit::PowerElectronicsModel(use_jac); - // Modeled after the problem in the paper - double RN = 1.0e4; - - // DG Params - static constexpr auto pi = std::numbers::pi_v; - - GridKit::DistributedGeneratorParameters parms1; - parms1.wb_ = 2.0 * 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 * 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 * pi * 50.0); - - double rline2 = 0.35; - double Lline2 = 0.58 / (2.0 * pi * 50.0); - - double rline3 = 0.23; - double Lline3 = 0.1 / (2.0 * pi * 50.0); - - // load parms - double rload1 = 3.0; - double Lload1 = 2.0 / (2.0 * pi * 50.0); - - double rload2 = 2.0; - double Lload2 = 1.0 / (2.0 * pi * 50.0); - - using SignalNode = GridKit::PowerElectronics::SignalNode; - SignalNode dg_signal; - - sysmodel->addNode(&dg_signal); - - using Bus = GridKit::PowerElectronics::MicrogridBus; - Bus bus1; - Bus bus2; - Bus bus3; - Bus bus4; - - sysmodel->addNode(&bus1); - sysmodel->addNode(&bus2); - sysmodel->addNode(&bus3); - sysmodel->addNode(&bus4); - - // 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, &dg_signal, &bus2); - sysmodel->addComponent(dg2); - - // dg 3 - 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, &dg_signal, &bus4); - sysmodel->addComponent(dg4); - - // Lines - - // line 1 - 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, &dg_signal, &bus2, &bus3); - sysmodel->addComponent(l2); - - // line 3 - 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, &dg_signal, &bus1); - sysmodel->addComponent(load1); - - // load 2 - GridKit::MicrogridLoad* load2 = new GridKit::MicrogridLoad(8, rload2, Lload2, &dg_signal, &bus3); - sysmodel->addComponent(load2); - - // Virtual PQ Buses - GridKit::MicrogridBusDQ* bus_para_1 = new GridKit::MicrogridBusDQ(9, RN, &bus1); - sysmodel->addComponent(bus_para_1); - - GridKit::MicrogridBusDQ* bus_para_2 = new GridKit::MicrogridBusDQ(10, RN, &bus2); - sysmodel->addComponent(bus_para_2); - - GridKit::MicrogridBusDQ* bus_para_3 = new GridKit::MicrogridBusDQ(11, RN, &bus3); - sysmodel->addComponent(bus_para_3); - - GridKit::MicrogridBusDQ* bus_para_4 = new GridKit::MicrogridBusDQ(12, RN, &bus4); - sysmodel->addComponent(bus_para_4); + // Build the four-generator microgrid network. + size_t N_size = 2; + ScaleMicrogridNetwork network(N_size); + assembleSystem(network, *sysmodel); + + // Generator parameters used to construct the initial conditions. + const auto& parms1 = network.DGParam_list[0]; + const auto& parms2 = network.DGParam_list[2]; sysmodel->allocate(); @@ -192,7 +59,7 @@ int main(int /* argc */, char const** /* argv */) } // since the intial P_com = 0 - y[dg_signal.getNodeConnection(0).idx_] = parms1.wb_; + y[network.dg_signal.getNodeConnection(0).idx_] = parms1.wb_; sysmodel->y().setDataUpdated(); sysmodel->yp().setDataUpdated(); @@ -228,7 +95,7 @@ int main(int /* argc */, char const** /* argv */) bool all_internal_diff = true; bool all_external_alg = true; - const size_t num_node_vars = bus1.size() + bus2.size() + bus3.size() + bus4.size() + dg_signal.size(); + const size_t num_node_vars = network.buses[0].size() + network.buses[1].size() + network.buses[2].size() + network.buses[3].size() + network.dg_signal.size(); for (size_t i = 0; i < sysmodel->size() - num_node_vars; i++) { diff --git a/examples/PowerElectronics/PowerElectronicsExamplesHelper/CMakeLists.txt b/examples/PowerElectronics/PowerElectronicsExamplesHelper/CMakeLists.txt new file mode 100644 index 000000000..7d41b162e --- /dev/null +++ b/examples/PowerElectronics/PowerElectronicsExamplesHelper/CMakeLists.txt @@ -0,0 +1,10 @@ +add_library(power_elec_microgrid_network INTERFACE) + +add_library(GridKit::power_elec_microgrid_network ALIAS power_elec_microgrid_network) + +target_link_libraries( + power_elec_microgrid_network + INTERFACE GridKit::power_elec_disgen + GridKit::power_elec_microbusdq + GridKit::power_elec_microline + GridKit::power_elec_microload) \ No newline at end of file diff --git a/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp b/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp new file mode 100644 index 000000000..d7da59762 --- /dev/null +++ b/examples/PowerElectronics/PowerElectronicsExamplesHelper/MicrogridNetwork.hpp @@ -0,0 +1,294 @@ +// MicrogridNetwork.hpp + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* + * Contains components and nodes that make up the scaled microgrid network. + * + * The network contains 2 * N_size IBRs and stores the physical components + * that make up the scale microgrid. + */ +template +struct ScaleMicrogridNetwork +{ + + using SignalNode = GridKit::PowerElectronics::SignalNode; + using Bus = GridKit::PowerElectronics::MicrogridBus; + using BusDQ = GridKit::MicrogridBusDQ; + using DGGenerator = GridKit::DistributedGenerator; + using Line = GridKit::MicrogridLine; + using Load = GridKit::MicrogridLoad; + using GenParams = GridKit::DistributedGeneratorParameters; + + size_t model_id_next; + size_t N_size; + SignalNode dg_signal; + std::vector buses; + std::vector busesDQ; + std::vector generators; + std::vector lines; + std::vector loads; + std::vector DGParam_list; + + ScaleMicrogridNetwork(size_t n_size) + : model_id_next(0), + N_size(n_size), + buses(2 * n_size), + busesDQ(2 * n_size, nullptr), + generators(2 * n_size, nullptr), + lines(2 * n_size - 1, nullptr), + loads(2 * n_size, nullptr), + DGParam_list(2 * n_size) + { + buildScaleMicrogridNetwork(); + } + + /** + * @brief Construct all components of the scaled microgrid network. + * + * Builds a microgrid containing @c 2*N_size generators and buses connected + * in a chain by transmission lines. Loads are connected to every other bus, + * and a virtual DQ bus is associated with each physical bus. + * + * The first two generators use the reference generator parameter set, while + * all remaining generators use the second parameter set. Line parameters + * alternate along the network, and the first load uses a different parameter + * set from the remaining loads. + * + * The created components are stored in this network and assigned unique model + * identifiers using @c model_id_next. + * + * @pre @c N_size is greater than zero. + * + * @post The network contains @c 2*N_size generators and virtual DQ buses. + * @post The network contains @c 2*N_size-1 transmission lines connecting + * consecutive buses. + * @post The network contains @c N_size loads connected to every other bus. + * @post @c DGParam_list contains the parameters associated with each generator. + * @post @c model_id_next is advanced for every component created. + * + * @note Components are dynamically allocated and their pointers are stored + * in the corresponding component vectors. + */ + void buildScaleMicrogridNetwork() + { + assert(N_size > 0); + // Every Bus has the same virtual resistance. This is due to numerical stability as mentioned in the paper. + ScalarT RN = 1.0e4; + + // TODO: add this as parameters + // DG Params Vector + // All DGs have the same set of parameters except for the first two. + GenParams 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; + + GenParams 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; + + DGParam_list.assign(2 * N_size, DG_parms2); + + // First two generators use parameters 1 + if (DGParam_list.size() >= 1) + { + DGParam_list[0] = DG_parms1; + } + if (DGParam_list.size() >= 2) + { + DGParam_list[1] = DG_parms1; + } + + // line vector params + // Every odd line has the same parameters and every even line has the same parameters + ScalarT rline1 = 0.23; + ScalarT Lline1 = 0.1 / (2.0 * M_PI * 50.0); + ScalarT rline2 = 0.35; + ScalarT 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 (IdxT 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. + ScalarT rload1 = 3.0; + ScalarT Lload1 = 2.0 / (2.0 * M_PI * 50.0); + ScalarT rload2 = 2.0; + ScalarT 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; + } + + // Create the reference generator + auto* dg_ref = new DGGenerator(model_id_next++, + DGParam_list[0], + true, + &dg_signal, + &buses[0]); + + generators[0] = dg_ref; + + // Create the remaining generators. + for (IdxT i = 1; i < 2 * N_size; i++) + { + auto* dg = new DGGenerator(model_id_next++, + DGParam_list[i], + false, + &dg_signal, + &buses[i]); + + generators[i] = dg; + } + + // Create transmission lines between consecutive buses. + for (IdxT i = 0; i < 2 * N_size - 1; i++) + { + auto* line_model = new Line(model_id_next++, + rline_list[i], + Lline_list[i], + &dg_signal, + &buses[i], + &buses[i + 1]); + + lines[i] = line_model; + } + + // Create loads on every other bus. + for (IdxT i = 0; i < N_size; i++) + { + auto* load_model = new Load(model_id_next++, + rload_list[i], + Lload_list[i], + &dg_signal, + &buses[2 * i]); + + loads[2 * i] = load_model; + } + + // Create and Add all the microgrid Virtual DQ Buses + for (IdxT i = 0; i < 2 * N_size; i++) + { + auto* virDQbus_model = new BusDQ(model_id_next++, + RN, + &buses[i]); + + busesDQ[i] = virDQbus_model; + } + } +}; + +/** + * @brief Assemble a scaled microgrid network into a power electronics model. + * + * Adds the signal node, physical buses, generators, transmission lines, + * loads, and virtual DQ buses stored in @p network to @p sys_model. + * + * This function does not construct or allocate any network components. + * + * @param[in] network Constructed scaled microgrid network whose components + * are added to the system model. + * @param[in,out] sys_model Power electronics model to which the network + * components and nodes are added. + * + * @pre @c network.N_size is greater than zero. + * @pre All component and node pointers referenced by @p network are valid. + * + * @post The signal node and all physical buses in @p network have been added + * to @p sys_model. + * @post All generators, transmission lines, loads, and virtual DQ buses in + * @p network have been added to @p sys_model. + * + * @note This function only assembles the network into the system model. It + * does not call PowerElectronicsModel::allocate(). + */ +template +void assembleSystem(ScaleMicrogridNetwork& network, GridKit::PowerElectronicsModel& sys_model) +{ + size_t N_size = network.N_size; + + // Ensure minimum size requirement + assert(N_size > 0); + + // Add all bus nodes + sys_model.addNode(&network.dg_signal); + + for (size_t i = 0; i < 2 * N_size; i++) + { + sys_model.addNode(&network.buses[i]); + } + + // Add all generators + for (IdxT i = 0; i < 2 * N_size; i++) + { + sys_model.addComponent(network.generators[i]); + } + + // Load all the Line components + for (IdxT i = 0; i < 2 * N_size - 1; i++) + { + sys_model.addComponent(network.lines[i]); + } + + // Load all the Load components + for (IdxT i = 0; i < 2 * N_size; i++) + { + if (network.loads[i] != nullptr) + { + sys_model.addComponent(network.loads[i]); + } + } + + // Add all the microgrid Virtual DQ Buses + for (IdxT i = 0; i < 2 * N_size; i++) + { + sys_model.addComponent(network.busesDQ[i]); + } +} diff --git a/examples/PowerElectronics/ScaleMicrogrid/CMakeLists.txt b/examples/PowerElectronics/ScaleMicrogrid/CMakeLists.txt index 0334a939b..277486306 100644 --- a/examples/PowerElectronics/ScaleMicrogrid/CMakeLists.txt +++ b/examples/PowerElectronics/ScaleMicrogrid/CMakeLists.txt @@ -1,12 +1,14 @@ add_executable(scalemicrogrid ScaleMicrogrid.cpp) add_executable(scalemicrogridarbitrary ScaleMicrogridArbitrary.cpp) + target_link_libraries( scalemicrogrid GridKit::power_elec_disgen GridKit::power_elec_microline GridKit::power_elec_microload GridKit::solvers_dyn - GridKit::power_elec_microbusdq) + GridKit::power_elec_microbusdq + GridKit::power_elec_microgrid_network) target_link_libraries( scalemicrogridarbitrary @@ -14,7 +16,8 @@ target_link_libraries( GridKit::power_elec_microline GridKit::power_elec_microload GridKit::solvers_dyn - GridKit::power_elec_microbusdq) + GridKit::power_elec_microbusdq + GridKit::power_elec_microgrid_network) add_test(NAME ScaleMicrogrid COMMAND $) install(TARGETS scalemicrogrid RUNTIME DESTINATION bin) diff --git a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp index cc8dc28ee..a0f3f0d1f 100644 --- a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp +++ b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogrid.cpp @@ -1,22 +1,14 @@ #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; @@ -94,143 +86,9 @@ int test(index_type Nsize, real_type error_tol, bool debug_output) std::cout << "Using default Nsize = 8.\n"; } - // Modeled after the problem in the paper - // Every Bus has the same virtual resistance. This is due to the 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. - static constexpr auto pi = std::numbers::pi_v; - - GridKit::DistributedGeneratorParameters DG_parms1; - DG_parms1.wb_ = 2.0 * 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 * 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 * Nsize, DG_parms2); - - DGParams_list[0] = DG_parms1; - 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 * pi * 50.0); - real_type rline2 = 0.35; - real_type Lline2 = 0.58 / (2.0 * pi * 50.0); - std::vector rline_list(2 * Nsize - 1, 0.0); - std::vector Lline_list(2 * Nsize - 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 * pi * 50.0); - real_type rload2 = 2.0; - real_type Lload2 = 1.0 / (2.0 * pi * 50.0); - - std::vector rload_list(Nsize, rload2); - std::vector Lload_list(Nsize, Lload2); - rload_list[0] = rload1; - Lload_list[0] = Lload1; - - using SignalNode = GridKit::PowerElectronics::SignalNode; - SignalNode dg_signal; - sys_model->addNode(&dg_signal); - - using Bus = GridKit::PowerElectronics::MicrogridBus; - std::unique_ptr[]> buses = std::make_unique[]>(2 * Nsize); - for (size_t i = 0; i < 2 * Nsize; i++) - { - buses[i] = std::make_unique(); - sys_model->addNode(buses[i].get()); - } - - // Create the reference DG - auto* dg_ref = new DistributedGenerator(0, - DGParams_list[0], - true, - &dg_signal, - buses[0].get()); - sys_model->addComponent(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 * Nsize; i++) - { - // current DG to add - auto* dg = new DistributedGenerator(model_id++, - DGParams_list[i], - false, - &dg_signal, - buses[i].get()); - sys_model->addComponent(dg); - } - - // Load all the Line compoenents - for (index_type i = 0; i < 2 * Nsize - 1; i++) - { - // line - auto* line_model = new MicrogridLine(model_id++, - rline_list[i], - Lline_list[i], - &dg_signal, - buses[i].get(), - buses[i + 1].get()); - sys_model->addComponent(line_model); - } - - // Load all the Load components - for (index_type i = 0; i < Nsize; i++) - { - auto* load_model = new MicrogridLoad(model_id++, - rload_list[i], - Lload_list[i], - &dg_signal, - buses[2 * i].get()); - sys_model->addComponent(load_model); - } - - // Add all the microgrid Virtual DQ Buses - for (index_type i = 0; i < 2 * Nsize; i++) - { - auto* virDQbus_model = new MicrogridBusDQ(model_id++, RN, buses[i].get()); - sys_model->addComponent(virDQbus_model); - } + // Build and assemble the scaled microgrid network. + ScaleMicrogridNetwork network(Nsize); + assembleSystem(network, *sys_model); // allocate all the intial conditions sys_model->allocate(); @@ -253,13 +111,15 @@ int test(index_type Nsize, real_type error_tol, bool debug_output) // Create initial derivatives specifics generated in MATLAB for (index_type i = 0; i < 2 * Nsize; i++) { - yp[13 * i - 1 + 2] = DGParams_list[i].Vn_; - yp[13 * i - 1 + 4] = DGParams_list[i].Kpv_ * DGParams_list[i].Vn_; - yp[13 * i - 1 + 6] = (DGParams_list[i].Kpc_ * DGParams_list[i].Kpv_ * DGParams_list[i].Vn_) / DGParams_list[i].Lf_; + const auto& params = network.DGParam_list[i]; + + yp[13 * i - 1 + 2] = params.Vn_; + yp[13 * i - 1 + 4] = params.Kpv_ * params.Vn_; + yp[13 * i - 1 + 6] = (params.Kpc_ * params.Kpv_ * params.Vn_) / params.Lf_; } // since the intial P_com = 0, the set the intial vector to the reference frame - y[dg_signal.getNodeConnection(0).idx_] = DG_parms1.wb_; + y[network.dg_signal.getNodeConnection(0).idx_] = network.DGParam_list[0].wb_; sys_model->y().setDataUpdated(); sys_model->yp().setDataUpdated(); diff --git a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp index a8ab6a4a1..f0488425f 100644 --- a/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp +++ b/examples/PowerElectronics/ScaleMicrogrid/ScaleMicrogridArbitrary.cpp @@ -1,20 +1,12 @@ #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; @@ -79,149 +71,9 @@ int printMicrogridSystems(index_type N_size) 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. - static constexpr auto pi = std::numbers::pi_v; - - GridKit::DistributedGeneratorParameters DG_parms1; - DG_parms1.wb_ = 2.0 * 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 * 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 * pi * 50.0); - real_type rline2 = 0.35; - real_type Lline2 = 0.58 / (2.0 * 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 * pi * 50.0); - real_type rload2 = 2.0; - real_type Lload2 = 1.0 / (2.0 * 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; - SignalNode dg_signal; - sys_model.addNode(&dg_signal); - - using Bus = GridKit::PowerElectronics::MicrogridBus; - std::unique_ptr[]> buses = std::make_unique[]>(2 * N_size); - for (size_t i = 0; i < 2 * N_size; i++) - { - buses[i] = std::make_unique(); - sys_model.addNode(buses[i].get()); - } - - // Create the reference DG - auto* dg_ref = new DistributedGenerator(0, - DGParams_list[0], - true, - &dg_signal, - buses[0].get()); - sys_model.addComponent(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].get()); - 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].get(), - buses[i + 1].get()); - 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].get()); - 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].get()); - sys_model.addComponent(virDQbus_model); - } + // Build and assemble the scaled microgrid network. + ScaleMicrogridNetwork network(N_size); + assembleSystem(network, sys_model); // allocate all the initial conditions sys_model.allocate(); @@ -236,16 +88,22 @@ int printMicrogridSystems(index_type N_size) yp[i] = 0.0; } + //------------------------------------------------------------------- // Create Initial derivatives specifics generated in MATLAB + //------------------------------------------------------------------- for (index_type i = 0; i < 2 * N_size; i++) { - yp[13 * i - 1 + 3] = DGParams_list[i].Vn_; - yp[13 * i - 1 + 5] = DGParams_list[i].Kpv_ * DGParams_list[i].Vn_; - yp[13 * i - 1 + 7] = (DGParams_list[i].Kpc_ * DGParams_list[i].Kpv_ * DGParams_list[i].Vn_) / DGParams_list[i].Lf_; + const auto& params = network.DGParam_list[i]; + + yp[13 * i - 1 + 3] = params.Vn_; + yp[13 * i - 1 + 5] = params.Kpv_ * params.Vn_; + yp[13 * i - 1 + 7] = (params.Kpc_ * params.Kpv_ * params.Vn_) / params.Lf_; } + //--------------------------------------------------------------------------- // since the initial P_com = 0, set the initial vector to the reference frame - y[dg_signal.getNodeConnection(0).idx_] = DG_parms1.wb_; + //--------------------------------------------------------------------------- + y[network.dg_signal.getNodeConnection(0).idx_] = network.DGParam_list[0].wb_; sys_model.y().setDataUpdated(); sys_model.yp().setDataUpdated(); diff --git a/tests/UnitTests/PowerElectronics/CMakeLists.txt b/tests/UnitTests/PowerElectronics/CMakeLists.txt index 74d50eb1e..55a0ff790 100644 --- a/tests/UnitTests/PowerElectronics/CMakeLists.txt +++ b/tests/UnitTests/PowerElectronics/CMakeLists.txt @@ -3,6 +3,17 @@ target_link_libraries( test_power_electronics_node PRIVATE GridKit::power_electronics_circuit_node GridKit::testing) +add_executable(test_power_electronics_component_clone runComponentCloneTests.cpp) +target_link_libraries( + test_power_electronics_component_clone + PRIVATE GridKit::power_elec_disgen + GridKit::power_elec_microline + GridKit::power_elec_microload + GridKit::power_elec_microbusdq + GridKit::testing) + add_test(NAME PowerElectronicsNodeTest COMMAND $) +add_test(NAME PowerElectronicsComponentCloneTest COMMAND $) install(TARGETS test_power_electronics_node RUNTIME DESTINATION bin) +install(TARGETS test_power_electronics_component_clone RUNTIME DESTINATION bin) diff --git a/tests/UnitTests/PowerElectronics/ComponentCloneTests.hpp b/tests/UnitTests/PowerElectronics/ComponentCloneTests.hpp new file mode 100644 index 000000000..5124442d8 --- /dev/null +++ b/tests/UnitTests/PowerElectronics/ComponentCloneTests.hpp @@ -0,0 +1,263 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace GridKit +{ + template + bool verifyComponentClone(ComponentT& component) + { + using RealT = typename CircuitComponent::RealT; + + bool success = true; + + auto* clone = dynamic_cast(component.clone()); + + if (clone == nullptr) + { + return false; + } + + /************************************************************************** + * Verify the Clone Initially Matches the Original + **************************************************************************/ + + success &= clone != &component; + success &= clone->size() == component.size(); + success &= clone->nnz() == component.nnz(); + success &= clone->getInternalSize() == component.getInternalSize(); + success &= clone->getExternSize() == component.getExternSize(); + success &= clone->getExternIndices() == component.getExternIndices(); + success &= clone->getIDcomponent() == component.getIDcomponent(); + + /************************************************************************** + * Verify Connection Independence + **************************************************************************/ + + for (IdxT i = 0; i < component.size(); ++i) + { + const IdxT connection = component.getNodeConnection(i); + + success &= clone->getNodeConnection(i) == connection; + + clone->setConnectionNodes(i, connection + 1); + + success &= component.getNodeConnection(i) == connection; + success &= clone->getNodeConnection(i) == connection + 1; + + clone->setConnectionNodes(i, connection); + } + + /************************************************************************** + * Verify State Independence + **************************************************************************/ + + auto checkVectorIndependence = [&success](auto& original, auto& copy) + { + success &= original.getSize() == copy.getSize(); + + if (original.getSize() == 0) + { + return; + } + + auto* original_data = original.getData(); + auto* copy_data = copy.getData(); + + success &= original_data != copy_data; + + const auto original_value = original_data[0]; + + copy_data[0] = original_value + 1.0; + + success &= original_data[0] == original_value; + success &= copy_data[0] == original_value + 1.0; + + copy_data[0] = original_value; + }; + + checkVectorIndependence(component.y(), clone->y()); + checkVectorIndependence(component.yp(), clone->yp()); + checkVectorIndependence(component.getResidual(), clone->getResidual()); + checkVectorIndependence(component.absoluteTolerance(), clone->absoluteTolerance()); + checkVectorIndependence(component.param(), clone->param()); + + /************************************************************************** + * Verify Jacobian Independence + **************************************************************************/ + + if (component.nnz() > 0) + { + auto* original_rows = component.jacobianCooRows(); + auto* original_cols = component.jacobianCooCols(); + auto* original_values = component.jacobianCooValues(); + + auto* clone_rows = clone->jacobianCooRows(); + auto* clone_cols = clone->jacobianCooCols(); + auto* clone_values = clone->jacobianCooValues(); + + success &= clone_rows != original_rows; + success &= clone_cols != original_cols; + success &= clone_values != original_values; + + for (IdxT i = 0; i < component.nnz(); ++i) + { + success &= clone_rows[i] == original_rows[i]; + success &= clone_cols[i] == original_cols[i]; + success &= clone_values[i] == original_values[i]; + } + + const IdxT original_row = original_rows[0]; + const IdxT original_col = original_cols[0]; + const RealT original_value = original_values[0]; + + clone_rows[0] = original_row + 1; + clone_cols[0] = original_col + 1; + clone_values[0] = original_value + 1.0; + + success &= original_rows[0] == original_row; + success &= original_cols[0] == original_col; + success &= original_values[0] == original_value; + + clone_rows[0] = original_row; + clone_cols[0] = original_col; + clone_values[0] = original_value; + } + + delete clone; + + return success; + } + + namespace Testing + { + template + class CircuitComponentCloneTests + { + using SignalNode = PowerElectronics::SignalNode; + using Bus = PowerElectronics::MicrogridBus; + using BusDQ = MicrogridBusDQ; + using Generator = DistributedGenerator; + using GeneratorParameters = DistributedGeneratorParameters; + using Line = MicrogridLine; + using Load = MicrogridLoad; + + public: + CircuitComponentCloneTests() + { + /************************************************************************** + * Construct Network Nodes + **************************************************************************/ + + signal_.allocate(); + + bus1_.allocate(); + bus2_.allocate(); + + /************************************************************************** + * Distributed Generator Parameters + **************************************************************************/ + + generator_parameters_.wb_ = 2.0 * M_PI * 50.0; + generator_parameters_.wc_ = 31.41; + generator_parameters_.mp_ = 9.4e-5; + generator_parameters_.Vn_ = 380.0; + generator_parameters_.nq_ = 1.3e-3; + generator_parameters_.F_ = 0.75; + generator_parameters_.Kiv_ = 420.0; + generator_parameters_.Kpv_ = 0.1; + generator_parameters_.Kic_ = 2.0e4; + generator_parameters_.Kpc_ = 15.0; + generator_parameters_.Cf_ = 5.0e-5; + generator_parameters_.rLf_ = 0.1; + generator_parameters_.Lf_ = 1.35e-3; + generator_parameters_.rLc_ = 0.03; + generator_parameters_.Lc_ = 0.35e-3; + + /************************************************************************** + * Construct Components + **************************************************************************/ + + generator_ = new Generator(1, generator_parameters_, true, &signal_, &bus1_); + + line_ = new Line(2, 0.23, 0.1 / (2.0 * M_PI * 50.0), &signal_, &bus1_, &bus2_); + + load_ = new Load(3, 3.0, 2.0 / (2.0 * M_PI * 50.0), &signal_, &bus1_); + + bus_dq_ = new BusDQ(4, 1.0e4, &bus1_); + + /************************************************************************** + * Allocate Components + **************************************************************************/ + + generator_->allocate(); + line_->allocate(); + load_->allocate(); + bus_dq_->allocate(); + } + + ~CircuitComponentCloneTests() + { + delete generator_; + delete line_; + delete load_; + delete bus_dq_; + } + + TestOutcome distributedGeneratorClone() + { + TestStatus success = true; + + success *= verifyComponentClone(*generator_); + + return success.report(__func__); + } + + TestOutcome microgridLineClone() + { + TestStatus success = true; + + success *= verifyComponentClone(*line_); + + return success.report(__func__); + } + + TestOutcome microgridLoadClone() + { + TestStatus success = true; + + success *= verifyComponentClone(*load_); + + return success.report(__func__); + } + + TestOutcome microgridBusDQClone() + { + TestStatus success = true; + + success *= verifyComponentClone(*bus_dq_); + + return success.report(__func__); + } + + private: + SignalNode signal_; + + Bus bus1_; + Bus bus2_; + + GeneratorParameters generator_parameters_; + + Generator* generator_{nullptr}; + Line* line_{nullptr}; + Load* load_{nullptr}; + BusDQ* bus_dq_{nullptr}; + }; + } // namespace Testing +} // namespace GridKit diff --git a/tests/UnitTests/PowerElectronics/runComponentCloneTests.cpp b/tests/UnitTests/PowerElectronics/runComponentCloneTests.cpp new file mode 100644 index 000000000..dfb5fa97f --- /dev/null +++ b/tests/UnitTests/PowerElectronics/runComponentCloneTests.cpp @@ -0,0 +1,15 @@ +#include "ComponentCloneTests.hpp" + +int main() +{ + GridKit::Testing::CircuitComponentCloneTests tests; + + GridKit::Testing::TestingResults result; + + result += tests.distributedGeneratorClone(); + result += tests.microgridLineClone(); + result += tests.microgridLoadClone(); + result += tests.microgridBusDQClone(); + + return result.summary(); +}