diff --git a/CHANGELOG.md b/CHANGELOG.md index 54c67fab0..183170f91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,8 @@ - Added LoadZIP model component type. - Added component model developer checklist to a README file. - Added IEEEST Stabilizer Model +- Added `BranchBase` abstract class and `BranchFactory` to support additional branch types (only LINE phasor $`\pi`$-model currently implemented). +- Generalized Bus terminal voltage and current accessors. ## v0.1 diff --git a/GridKit/Model/PhasorDynamics/Branch/Branch.hpp b/GridKit/Model/PhasorDynamics/Branch/Branch.hpp index 5355b0b8a..3dbe60305 100644 --- a/GridKit/Model/PhasorDynamics/Branch/Branch.hpp +++ b/GridKit/Model/PhasorDynamics/Branch/Branch.hpp @@ -9,6 +9,7 @@ #pragma once #include +#include #include #include #include @@ -38,7 +39,7 @@ namespace GridKit * */ template - class Branch : public Component + class Branch : public BranchBase { using Component::gridkit_component_id_; using Component::size_; @@ -57,6 +58,8 @@ namespace GridKit using Component::J_vals_buffer_; using Component::variable_indices_; using Component::residual_indices_; + using BranchBase::ports_; + using BranchBase::branch_id_; public: using RealT = typename Component::RealT; @@ -75,6 +78,8 @@ namespace GridKit virtual int tagDifferentiable() override final; virtual int evaluateResidual() override final; virtual int evaluateJacobian() override final; + virtual int setBranchID(IdxT) override final; + virtual int verifyPorts() const override final; virtual int verify() const override final { @@ -115,42 +120,42 @@ namespace GridKit ScalarT& Vr1() { - return bus1_->Vr(); + return this->port(0)->v(0); } ScalarT& Vi1() { - return bus1_->Vi(); + return this->port(0)->v(1); } ScalarT& Ir1() { - return bus1_->Ir(); + return this->port(0)->i(0); } ScalarT& Ii1() { - return bus1_->Ii(); + return this->port(0)->i(1); } ScalarT& Vr2() { - return bus2_->Vr(); + return this->port(1)->v(0); } ScalarT& Vi2() { - return bus2_->Vi(); + return this->port(1)->v(1); } ScalarT& Ir2() { - return bus2_->Ir(); + return this->port(1)->i(0); } ScalarT& Ii2() { - return bus2_->Ii(); + return this->port(1)->i(1); } public: @@ -160,14 +165,10 @@ namespace GridKit __attribute__((always_inline)) inline int evaluateBusResidual22(ScalarT*, ScalarT*, ScalarT*, ScalarT*); private: - bus_type* bus1_; - bus_type* bus2_; - RealT R_{0.0}; - RealT X_{0.0}; - RealT G_{0.0}; - RealT B_{0.0}; - IdxT bus1_id_{0}; - IdxT bus2_id_{0}; + RealT R_{0.0}; + RealT X_{0.0}; + RealT G_{0.0}; + RealT B_{0.0}; /* Derived parameters */ RealT b_; diff --git a/GridKit/Model/PhasorDynamics/Branch/BranchData.hpp b/GridKit/Model/PhasorDynamics/Branch/BranchData.hpp index 98528c3d1..df679813d 100644 --- a/GridKit/Model/PhasorDynamics/Branch/BranchData.hpp +++ b/GridKit/Model/PhasorDynamics/Branch/BranchData.hpp @@ -63,6 +63,17 @@ namespace GridKit using Parameters = BranchParameters; using Ports = BranchPorts; using MonitorableVariables = BranchMonitorableVariables; + + /// @brief Concrete branch kind this data configures. + enum class BranchType + { + INVALID, + LINE, ///< Phasor pi-model (Branch) + LUMPED_EMT, ///< reserved, not yet implemented + TRANSFORMER, ///< reserved, not yet implemented + }; + + BranchType branch_type{BranchType::LINE}; }; } // namespace PhasorDynamics } // namespace GridKit diff --git a/GridKit/Model/PhasorDynamics/Branch/BranchDataJSONParser.hpp b/GridKit/Model/PhasorDynamics/Branch/BranchDataJSONParser.hpp new file mode 100644 index 000000000..7eca29000 --- /dev/null +++ b/GridKit/Model/PhasorDynamics/Branch/BranchDataJSONParser.hpp @@ -0,0 +1,50 @@ +/** + * @file BranchDataJSONParser.hpp + * @author Luke Lowery (lukel@tamu.edu) + * @brief JSON parser for BranchData. + */ + +#pragma once + +#include + +#include + +#include +#include +#include + +namespace GridKit +{ + namespace PhasorDynamics + { + using json = nlohmann::json; + using Log = ::GridKit::Utilities::Logger; + + /// JSON parser for `BranchData`: fills the generic `ComponentData` + /// fields, then maps the JSON `class` string to `BranchType`. + template + void from_json(const json& j, BranchData& bd) + { + // Qualified call with explicit template args: prevents rebinding + // to this overload instead of the generic ComponentData from_json. + using BaseT = ComponentData; + ::GridKit::PhasorDynamics::from_json( + j, static_cast(bd)); + + auto string_class = j.at("class").get(); + if (string_class == "Branch") + { + bd.branch_type = BranchData::BranchType::LINE; + } + else + { + Log::error() << "\n\tInvalid branch class: \"" << string_class + << "\".\n\tSee the device with \"id\": \"" + << bd.disambiguation_string + << "\" in the \"devices\" list of your JSON file." + << std::endl; + } + } + } // namespace PhasorDynamics +} // namespace GridKit diff --git a/GridKit/Model/PhasorDynamics/Branch/BranchEnzyme.cpp b/GridKit/Model/PhasorDynamics/Branch/BranchEnzyme.cpp index 535d944cd..99322ec6d 100644 --- a/GridKit/Model/PhasorDynamics/Branch/BranchEnzyme.cpp +++ b/GridKit/Model/PhasorDynamics/Branch/BranchEnzyme.cpp @@ -38,47 +38,47 @@ namespace GridKit GridKit::Enzyme::Sparse::MemberFunctions::BusResidual11, ScalarT, IdxT>::eval(this, - static_cast(bus1_->size()), - static_cast((bus1_->y()).size()), - (bus1_->getResidualIndices()).data(), - (bus1_->getVariableIndices()).data(), + static_cast(this->port(0)->size()), + static_cast((this->port(0)->y()).size()), + (this->port(0)->getResidualIndices()).data(), + (this->port(0)->getVariableIndices()).data(), y_.data(), yp_.data(), - (bus1_->y()).data(), + (this->port(0)->y()).data(), J_rows_buffer_, J_cols_buffer_, J_vals_buffer_, - bus1_->getJacobian()); + this->port(0)->getJacobian()); // Bus 2 diagonal Jacobian block owned by the bus GridKit::Enzyme::Sparse::DhDwb, GridKit::Enzyme::Sparse::MemberFunctions::BusResidual22, ScalarT, IdxT>::eval(this, - static_cast(bus2_->size()), - static_cast((bus2_->y()).size()), - (bus2_->getResidualIndices()).data(), - (bus2_->getVariableIndices()).data(), + static_cast(this->port(1)->size()), + static_cast((this->port(1)->y()).size()), + (this->port(1)->getResidualIndices()).data(), + (this->port(1)->getVariableIndices()).data(), y_.data(), yp_.data(), - (bus2_->y()).data(), + (this->port(1)->y()).data(), J_rows_buffer_, J_cols_buffer_, J_vals_buffer_, - bus2_->getJacobian()); + this->port(1)->getJacobian()); // Off-diagonal Jacobian block (Bus2 variables) owned by the branch GridKit::Enzyme::Sparse::DhDwb, GridKit::Enzyme::Sparse::MemberFunctions::BusResidual12, ScalarT, IdxT>::eval(this, - static_cast(bus1_->size()), - static_cast((bus2_->y()).size()), - (bus1_->getResidualIndices()).data(), - (bus2_->getVariableIndices()).data(), + static_cast(this->port(0)->size()), + static_cast((this->port(1)->y()).size()), + (this->port(0)->getResidualIndices()).data(), + (this->port(1)->getVariableIndices()).data(), y_.data(), yp_.data(), - (bus2_->y()).data(), + (this->port(1)->y()).data(), J_rows_buffer_, J_cols_buffer_, J_vals_buffer_, @@ -90,13 +90,13 @@ namespace GridKit GridKit::Enzyme::Sparse::MemberFunctions::BusResidual21, ScalarT, IdxT>::eval(this, - static_cast(bus2_->size()), - static_cast((bus1_->y()).size()), - (bus2_->getResidualIndices()).data(), - (bus1_->getVariableIndices()).data(), + static_cast(this->port(1)->size()), + static_cast((this->port(0)->y()).size()), + (this->port(1)->getResidualIndices()).data(), + (this->port(0)->getVariableIndices()).data(), y_.data(), yp_.data(), - (bus1_->y()).data(), + (this->port(0)->y()).data(), J_rows_buffer_, J_cols_buffer_, J_vals_buffer_, diff --git a/GridKit/Model/PhasorDynamics/Branch/BranchFactory.hpp b/GridKit/Model/PhasorDynamics/Branch/BranchFactory.hpp new file mode 100644 index 000000000..f05e952f4 --- /dev/null +++ b/GridKit/Model/PhasorDynamics/Branch/BranchFactory.hpp @@ -0,0 +1,71 @@ +/** + * @file BranchFactory.hpp + * @author Luke Lowery (lukel@tamu.edu) + * @brief Factory that constructs concrete BranchBase subclasses from BranchData. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include + +namespace GridKit +{ + namespace PhasorDynamics + { + /** + * @brief Constructs a concrete `BranchBase` from `BranchData`, dispatching + * on `BranchData::BranchType`. + * + * Structural bus/branch compatibility is not checked here; the concrete + * branch's `verifyPorts()` (run from `allocate()`) is responsible. + * + * Throws `std::runtime_error` if `branch_type` is unrecognized so + * misconfiguration fails at construction rather than as a `nullptr` + * dereference later. + */ + template + class BranchFactory + { + public: + using RealT = typename Model::Evaluator::RealT; + using BranchData = GridKit::PhasorDynamics::BranchData; + using BranchTypeT = typename GridKit::PhasorDynamics::BranchData::BranchType; + using bus_type = BusBase; + using Log = ::GridKit::Utilities::Logger; + + BranchFactory() = delete; + + /** + * @brief Construct a concrete branch selected by `data.branch_type`. + * + * @param data branch data; `branch_type` selects the concrete type. + * @param bus1 bus attached to port 0. + * @param bus2 bus attached to port 1. + * @return owning pointer to a newly-allocated concrete branch. + * @throws std::runtime_error if `branch_type` is unrecognized. + */ + static BranchBase* create(const BranchData& data, + bus_type* bus1, + bus_type* bus2) + { + switch (data.branch_type) + { + case BranchTypeT::LINE: + return new Branch(bus1, bus2, data); + default: + Log::error() << "BranchFactory: unrecognized branch_type " + << static_cast(data.branch_type) << std::endl; + throw std::runtime_error( + "BranchFactory::create: unrecognized branch_type " + + std::to_string(static_cast(data.branch_type))); + } + } + }; + } // namespace PhasorDynamics +} // namespace GridKit diff --git a/GridKit/Model/PhasorDynamics/Branch/BranchImpl.hpp b/GridKit/Model/PhasorDynamics/Branch/BranchImpl.hpp index bcb0c268d..a53db86ef 100644 --- a/GridKit/Model/PhasorDynamics/Branch/BranchImpl.hpp +++ b/GridKit/Model/PhasorDynamics/Branch/BranchImpl.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -28,16 +29,13 @@ namespace GridKit */ template Branch::Branch(bus_type* bus1, bus_type* bus2) - : bus1_(bus1), - bus2_(bus2), - R_(0.0), + : R_(0.0), X_(0.01), G_(0.0), - B_(0.0), - bus1_id_(0), - bus2_id_(0) + B_(0.0) { - size_ = 0; + this->ports_ = {bus1, bus2}; + size_ = 0; setDerivedParams(); } @@ -60,27 +58,22 @@ namespace GridKit RealT X, RealT G, RealT B) - : bus1_(bus1), - bus2_(bus2), - R_(R), + : R_(R), X_(X), G_(G), - B_(B), - bus1_id_(0), - bus2_id_(0) + B_(B) { + this->ports_ = {bus1, bus2}; setDerivedParams(); } template Branch::Branch(bus_type* bus1, bus_type* bus2, const model_data_type& data) - : bus1_(bus1), - bus2_(bus2), - monitor_(std::make_unique(data)) + : monitor_(std::make_unique(data)) { + this->ports_ = {bus1, bus2}; initializeParameters(data); initializeMonitor(); - size_ = 0; setDerivedParams(); } @@ -107,12 +100,48 @@ namespace GridKit return 0; } + template + int Branch::setBranchID(IdxT branch_id) + { + branch_id_ = branch_id; + return 0; + } + + template + int Branch::verifyPorts() const + { + if (this->portCount() != 2) + { + throw std::runtime_error( + "Branch requires exactly 2 ports, got " + + std::to_string(this->portCount())); + } + + for (IdxT k = 0; k < this->portCount(); ++k) + { + if (!this->ports_[static_cast(k)]) + { + throw std::runtime_error( + "Branch port " + std::to_string(k) + " is null"); + } + if (this->ports_[static_cast(k)]->count() != 2) + { + throw std::runtime_error( + "Branch requires port width 2, but port " + std::to_string(k) + + " has width " + + std::to_string(this->ports_[static_cast(k)]->count())); + } + } + return 0; + } + /*! * @brief allocate method computes sparsity pattern of the Jacobian. */ template int Branch::allocate() { + this->verifyPorts(); // std::cout << "Allocate Branch..." << std::endl; wb_.resize(2); @@ -274,16 +303,6 @@ namespace GridKit { B_ = std::get(data.parameters.at(model_data_type::Parameters::B)); } - - if (data.ports.contains(model_data_type::Ports::bus1)) - { - bus1_id_ = data.ports.at(model_data_type::Ports::bus1); - } - - if (data.ports.contains(model_data_type::Ports::bus2)) - { - bus2_id_ = data.ports.at(model_data_type::Ports::bus2); - } } template diff --git a/GridKit/Model/PhasorDynamics/Branch/CMakeLists.txt b/GridKit/Model/PhasorDynamics/Branch/CMakeLists.txt index 3325ea604..12c7e104b 100644 --- a/GridKit/Model/PhasorDynamics/Branch/CMakeLists.txt +++ b/GridKit/Model/PhasorDynamics/Branch/CMakeLists.txt @@ -7,7 +7,9 @@ set(_install_headers Branch.hpp - BranchData.hpp) + BranchData.hpp + BranchDataJSONParser.hpp + BranchFactory.hpp) if(GRIDKIT_ENABLE_ENZYME) gridkit_add_library(phasor_dynamics_branch diff --git a/GridKit/Model/PhasorDynamics/Branch/README.md b/GridKit/Model/PhasorDynamics/Branch/README.md index 2f6ed7e1a..3b78ac527 100644 --- a/GridKit/Model/PhasorDynamics/Branch/README.md +++ b/GridKit/Model/PhasorDynamics/Branch/README.md @@ -4,6 +4,12 @@ Transmission lines and different types of transformers (traditional, Load Tap-Changing transformers (LTC) and Phase Angle Regulators (PARs)) can be modeled with a common branch model. +Concrete branch models derive from the abstract `BranchBase` and are +constructed through `BranchFactory`, dispatching on `BranchData::BranchType`. +The LINE type documented below is the phasor $`\pi`$-model and is currently +the only implemented branch. LUMPED_EMT and TRANSFORMER types are reserved +for future implementation. + The most common circuit that is used to represent the transmission line model is $`\pi`$ circuit as shown in Figure 1. The positive flow direction is into buses. Commonly used convention is to define positive direction to be from @@ -81,7 +87,7 @@ None. \end{aligned} ``` -# Model Outputs +## Model Outputs Real and imaginary current at the branch's two buses are model variables of the branch model: $I_{r1}$, $I_{i1}$, $I_{r2}$, @@ -110,7 +116,7 @@ where the complex power is defined as $S=VI^{\ast}=(V_r + j V_i)(I_r - jI_i)$ Real and reactive power are oriented leaving the branch (i.e. entering the bus). -# Transformer Branch Model +## Transformer Branch Model **Note: Transformer model not yet implemented** diff --git a/GridKit/Model/PhasorDynamics/BranchBase.hpp b/GridKit/Model/PhasorDynamics/BranchBase.hpp new file mode 100644 index 000000000..8e02f10c9 --- /dev/null +++ b/GridKit/Model/PhasorDynamics/BranchBase.hpp @@ -0,0 +1,69 @@ +/** + * @file BranchBase.hpp + * @author Luke Lowery (lukel@tamu.edu) + * @brief Abstract base class for phasor-dynamics branch models. + */ + +#pragma once + +#include + +#include +#include + +namespace GridKit +{ + namespace PhasorDynamics + { + template + class BusBase; + + /** + * @brief Abstract base class for phasor-dynamics branch models. + * + * Provides the common structural contract for branches: `BusBase*` ports, + * a branch ID, and a `verifyPorts()` hook for concrete subclasses to + * assert per-port width compatibility. + */ + template + class BranchBase : public Component + { + public: + using bus_type = BusBase; + + BranchBase() = default; + virtual ~BranchBase() = default; + + bus_type* port(IdxT k) + { + return ports_[static_cast(k)]; + } + + const bus_type* port(IdxT k) const + { + return ports_[static_cast(k)]; + } + + IdxT portCount() const + { + return static_cast(ports_.size()); + } + + virtual int setBranchID(IdxT) = 0; + + virtual const IdxT branchID() const + { + return branch_id_; + } + + /// Called from allocate() to assert per-port width matches the concrete + /// branch's physics. Throws std::runtime_error on mismatch. + virtual int verifyPorts() const = 0; + + protected: + std::vector ports_; + IdxT branch_id_{INVALID_INDEX}; + }; + + } // namespace PhasorDynamics +} // namespace GridKit diff --git a/GridKit/Model/PhasorDynamics/Bus/Bus.hpp b/GridKit/Model/PhasorDynamics/Bus/Bus.hpp index a94afe863..b24de55da 100644 --- a/GridKit/Model/PhasorDynamics/Bus/Bus.hpp +++ b/GridKit/Model/PhasorDynamics/Bus/Bus.hpp @@ -53,44 +53,29 @@ namespace GridKit return BusTypeT::DEFAULT; } - virtual ScalarT& Vr() override final + virtual IdxT count() const override final { - return y_[0]; + return 2; } - virtual const ScalarT& Vr() const override final + virtual ScalarT& v(IdxT k) override final { - return y_[0]; + return y_[static_cast(k)]; } - virtual ScalarT& Vi() override final + virtual const ScalarT& v(IdxT k) const override final { - return y_[1]; + return y_[static_cast(k)]; } - virtual const ScalarT& Vi() const override final + virtual ScalarT& i(IdxT k) override final { - return y_[1]; + return f_[static_cast(k)]; } - virtual ScalarT& Ir() override final + virtual const ScalarT& i(IdxT k) const override final { - return f_[0]; - } - - virtual const ScalarT& Ir() const override final - { - return f_[0]; - } - - virtual ScalarT& Ii() override final - { - return f_[1]; - } - - virtual const ScalarT& Ii() const override final - { - return f_[1]; + return f_[static_cast(k)]; } private: diff --git a/GridKit/Model/PhasorDynamics/Bus/BusFactory.hpp b/GridKit/Model/PhasorDynamics/Bus/BusFactory.hpp index c9898a5d2..f291e9d85 100644 --- a/GridKit/Model/PhasorDynamics/Bus/BusFactory.hpp +++ b/GridKit/Model/PhasorDynamics/Bus/BusFactory.hpp @@ -32,7 +32,10 @@ namespace GridKit bus = new BusInfinite(data); break; default: - // Throw exception + // TODO: align with BranchFactory::create — throw std::runtime_error on + // unrecognized bus_type instead of logging and returning nullptr, so + // misconfiguration fails at construction rather than propagating a + // null pointer through SystemModel::build. std::cout << "Bus type " << static_cast(data.bus_type) << " unrecognized.\n"; } return bus; diff --git a/GridKit/Model/PhasorDynamics/Bus/BusInfinite.hpp b/GridKit/Model/PhasorDynamics/Bus/BusInfinite.hpp index 9f9866994..f7869bed5 100644 --- a/GridKit/Model/PhasorDynamics/Bus/BusInfinite.hpp +++ b/GridKit/Model/PhasorDynamics/Bus/BusInfinite.hpp @@ -47,56 +47,34 @@ namespace GridKit return BusTypeT::SLACK; } - virtual ScalarT& Vr() override final + virtual IdxT count() const override final { - return Vr_; + return 2; } - virtual const ScalarT& Vr() const override final + virtual ScalarT& v(IdxT k) override final { - return Vr_; + return v_[static_cast(k)]; } - virtual ScalarT& Vi() override final + virtual const ScalarT& v(IdxT k) const override final { - return Vi_; + return v_[static_cast(k)]; } - virtual const ScalarT& Vi() const override final + virtual ScalarT& i(IdxT k) override final { - return Vi_; + return i_[static_cast(k)]; } - virtual ScalarT& Ir() override final + virtual const ScalarT& i(IdxT k) const override final { - return Ir_; - } - - virtual const ScalarT& Ir() const override final - { - return Ir_; - } - - virtual ScalarT& Ii() override final - { - return Ii_; - } - - virtual const ScalarT& Ii() const override final - { - return Ii_; + return i_[static_cast(k)]; } private: - ScalarT Vr_{0.0}; - ScalarT Vi_{0.0}; - ScalarT Ir_{0.0}; - ScalarT Ii_{0.0}; - - ScalarT VrB_{0.0}; - ScalarT ViB_{0.0}; - ScalarT IrB_{0.0}; - ScalarT IiB_{0.0}; + ScalarT v_[2]{}; + ScalarT i_[2]{}; }; } // namespace PhasorDynamics diff --git a/GridKit/Model/PhasorDynamics/Bus/BusInfiniteImpl.hpp b/GridKit/Model/PhasorDynamics/Bus/BusInfiniteImpl.hpp index 56d05d82a..8a74a4051 100644 --- a/GridKit/Model/PhasorDynamics/Bus/BusInfiniteImpl.hpp +++ b/GridKit/Model/PhasorDynamics/Bus/BusInfiniteImpl.hpp @@ -37,7 +37,7 @@ namespace GridKit */ template BusInfinite::BusInfinite(ScalarT Vr, ScalarT Vi) - : Vr_(Vr), Vi_(Vi) + : v_{Vr, Vi} { size_ = 0; } @@ -56,8 +56,7 @@ namespace GridKit template BusInfinite::BusInfinite(const DataT& data) : BusBase(data), - Vr_(data.Vr0), - Vi_(data.Vi0) + v_{ScalarT(data.Vr0), ScalarT(data.Vi0)} { size_ = 0; } @@ -109,8 +108,8 @@ namespace GridKit * * Infinite bus does not compute residuals, so here we just reset * current values to zero. Components connected to the infinite bus - * will add their currents to Ir_ and Ii_. The resultant will be slack - * current that the infinite bus has to pick up. + * will add their currents to i_[0] and i_[1]. The resultant will be + * the slack current that the infinite bus has to pick up. * * @warning This implementation assumes bus residuals are always evaluated * _before_ component model residuals. @@ -119,8 +118,8 @@ namespace GridKit template int BusInfinite::evaluateResidual() { - Ir_ = 0.0; - Ii_ = 0.0; + i_[0] = 0.0; + i_[1] = 0.0; return 0; } diff --git a/GridKit/Model/PhasorDynamics/BusBase.hpp b/GridKit/Model/PhasorDynamics/BusBase.hpp index b2fc397d2..a0f93baa4 100644 --- a/GridKit/Model/PhasorDynamics/BusBase.hpp +++ b/GridKit/Model/PhasorDynamics/BusBase.hpp @@ -73,14 +73,21 @@ namespace GridKit msa = max_steps_; } - virtual ScalarT& Vr() = 0; - virtual const ScalarT& Vr() const = 0; - virtual ScalarT& Vi() = 0; - virtual const ScalarT& Vi() const = 0; - virtual ScalarT& Ir() = 0; - virtual const ScalarT& Ir() const = 0; - virtual ScalarT& Ii() = 0; - virtual const ScalarT& Ii() const = 0; + /// @brief Number of terminal slots exposed by this bus. + /// + /// Phasor-domain buses expose 2 slots (real and imaginary components of + /// terminal voltage and current). Future EMT-domain buses will expose 3 + /// slots (abc phases). Branch models consult this value at allocate() + /// time to verify structural compatibility with connected buses. + virtual IdxT count() const = 0; + + /// @brief Access terminal voltage slot @p k. + virtual ScalarT& v(IdxT k) = 0; + virtual const ScalarT& v(IdxT k) const = 0; + + /// @brief Access terminal current-balance residual slot @p k. + virtual ScalarT& i(IdxT k) = 0; + virtual const ScalarT& i(IdxT k) const = 0; std::vector& y() override { diff --git a/GridKit/Model/PhasorDynamics/BusBaseImpl.hpp b/GridKit/Model/PhasorDynamics/BusBaseImpl.hpp index 5611b8597..621b7b99e 100644 --- a/GridKit/Model/PhasorDynamics/BusBaseImpl.hpp +++ b/GridKit/Model/PhasorDynamics/BusBaseImpl.hpp @@ -14,13 +14,13 @@ namespace GridKit { using Variable = typename BusData::MonitorableVariables; monitor_->set(Variable::Vr, [this] - { return Vr(); }); + { return v(0); }); monitor_->set(Variable::Vi, [this] - { return Vi(); }); + { return v(1); }); monitor_->set(Variable::Vm, [this] - { return std::sqrt(Vr() * Vr() + Vi() * Vi()); }); + { return std::sqrt(v(0) * v(0) + v(1) * v(1)); }); monitor_->set(Variable::Va, [this] - { return std::atan2(Vi(), Vr()); }); + { return std::atan2(v(1), v(0)); }); } template diff --git a/GridKit/Model/PhasorDynamics/BusFault/BusFault.hpp b/GridKit/Model/PhasorDynamics/BusFault/BusFault.hpp index ba0d4784f..cd3309071 100644 --- a/GridKit/Model/PhasorDynamics/BusFault/BusFault.hpp +++ b/GridKit/Model/PhasorDynamics/BusFault/BusFault.hpp @@ -89,22 +89,22 @@ namespace GridKit ScalarT& Vr() { - return bus_->Vr(); + return bus_->v(0); } ScalarT& Vi() { - return bus_->Vi(); + return bus_->v(1); } ScalarT& Ir() { - return bus_->Ir(); + return bus_->i(0); } ScalarT& Ii() { - return bus_->Ii(); + return bus_->i(1); } public: diff --git a/GridKit/Model/PhasorDynamics/CMakeLists.txt b/GridKit/Model/PhasorDynamics/CMakeLists.txt index b83192684..dcbac1d17 100644 --- a/GridKit/Model/PhasorDynamics/CMakeLists.txt +++ b/GridKit/Model/PhasorDynamics/CMakeLists.txt @@ -11,6 +11,7 @@ gridkit_add_library(phasor_dynamics_core SystemModelData.cpp HEADERS BusBase.hpp + BranchBase.hpp Component.hpp ComponentData.hpp ComponentLibrary.hpp diff --git a/GridKit/Model/PhasorDynamics/Exciter/IEEET1/Ieeet1Impl.hpp b/GridKit/Model/PhasorDynamics/Exciter/IEEET1/Ieeet1Impl.hpp index 2cc266605..78d5c6639 100644 --- a/GridKit/Model/PhasorDynamics/Exciter/IEEET1/Ieeet1Impl.hpp +++ b/GridKit/Model/PhasorDynamics/Exciter/IEEET1/Ieeet1Impl.hpp @@ -210,8 +210,8 @@ namespace GridKit } // Terminal Voltage - ScalarT vreal = bus_->Vr(); - ScalarT vimag = bus_->Vi(); + ScalarT vreal = bus_->v(0); + ScalarT vimag = bus_->v(1); ScalarT Ec = std::sqrt(vreal * vreal + vimag * vimag); // Saturation at the initial operating point @@ -369,8 +369,8 @@ namespace GridKit } // Bus voltages - wb_[0] = bus_->Vr(); - wb_[1] = bus_->Vi(); + wb_[0] = bus_->v(0); + wb_[1] = bus_->v(1); // Residual evaluation evaluateInternalResidual(y_.data(), yp_.data(), wb_.data(), ws_.data(), f_.data()); diff --git a/GridKit/Model/PhasorDynamics/Load/Load.hpp b/GridKit/Model/PhasorDynamics/Load/Load.hpp index edbc42dca..96c10555f 100644 --- a/GridKit/Model/PhasorDynamics/Load/Load.hpp +++ b/GridKit/Model/PhasorDynamics/Load/Load.hpp @@ -85,22 +85,22 @@ namespace GridKit ScalarT& Vr() { - return bus_->Vr(); + return bus_->v(0); } ScalarT& Vi() { - return bus_->Vi(); + return bus_->v(1); } ScalarT& Ir() { - return bus_->Ir(); + return bus_->i(0); } ScalarT& Ii() { - return bus_->Ii(); + return bus_->i(1); } const Model::VariableMonitorBase* getMonitor() const override; diff --git a/GridKit/Model/PhasorDynamics/LoadZIP/LoadZIP.hpp b/GridKit/Model/PhasorDynamics/LoadZIP/LoadZIP.hpp index 6ebfbd029..fa93f85bd 100644 --- a/GridKit/Model/PhasorDynamics/LoadZIP/LoadZIP.hpp +++ b/GridKit/Model/PhasorDynamics/LoadZIP/LoadZIP.hpp @@ -101,22 +101,22 @@ namespace GridKit ScalarT& Vr() { - return bus_->Vr(); + return bus_->v(0); } ScalarT& Vi() { - return bus_->Vi(); + return bus_->v(1); } ScalarT& Ir() { - return bus_->Ir(); + return bus_->i(0); } ScalarT& Ii() { - return bus_->Ii(); + return bus_->i(1); } const Model::VariableMonitorBase* getMonitor() const override; diff --git a/GridKit/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.hpp b/GridKit/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.hpp index 0b08cd197..63fbd7411 100644 --- a/GridKit/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.hpp +++ b/GridKit/Model/PhasorDynamics/SynchronousMachine/GENROUwS/Genrou.hpp @@ -163,22 +163,22 @@ namespace GridKit ScalarT& Vr() { - return bus_->Vr(); + return bus_->v(0); } ScalarT& Vi() { - return bus_->Vi(); + return bus_->v(1); } ScalarT& Ir() { - return bus_->Ir(); + return bus_->i(0); } ScalarT& Ii() { - return bus_->Ii(); + return bus_->i(1); } public: diff --git a/GridKit/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.hpp b/GridKit/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.hpp index 514fc1d5d..414edec55 100644 --- a/GridKit/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.hpp +++ b/GridKit/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.hpp @@ -102,22 +102,22 @@ namespace GridKit ScalarT& Vr() { - return bus_->Vr(); + return bus_->v(0); } ScalarT& Vi() { - return bus_->Vi(); + return bus_->v(1); } ScalarT& Ir() { - return bus_->Ir(); + return bus_->i(0); } ScalarT& Ii() { - return bus_->Ii(); + return bus_->i(1); } public: diff --git a/GridKit/Model/PhasorDynamics/SystemModel.hpp b/GridKit/Model/PhasorDynamics/SystemModel.hpp index 527818383..492b23f5e 100644 --- a/GridKit/Model/PhasorDynamics/SystemModel.hpp +++ b/GridKit/Model/PhasorDynamics/SystemModel.hpp @@ -13,6 +13,7 @@ #include // Include all components +#include #include namespace GridKit @@ -120,7 +121,7 @@ namespace GridKit bus2_index = branchdata.ports.at(BranchData::Ports::bus2); } - auto* branch = new Branch(getBus(bus1_index), getBus(bus2_index), branchdata); + auto* branch = BranchFactory::create(branchdata, getBus(bus1_index), getBus(bus2_index)); addComponent(branch); } diff --git a/GridKit/Model/PhasorDynamics/SystemModelDataJSONParser.hpp b/GridKit/Model/PhasorDynamics/SystemModelDataJSONParser.hpp index 35f516764..a46c4012d 100644 --- a/GridKit/Model/PhasorDynamics/SystemModelDataJSONParser.hpp +++ b/GridKit/Model/PhasorDynamics/SystemModelDataJSONParser.hpp @@ -5,6 +5,7 @@ #include +#include #include #include #include diff --git a/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp b/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp index 8f5c7f083..37e8120af 100644 --- a/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp +++ b/examples/PhasorDynamics/Tiny/ThreeBus/Basic/ThreeBusBasic.cpp @@ -116,6 +116,7 @@ int main() data.branch[0].parameters[BranchParameters::X] = 0.21; data.branch[0].parameters[BranchParameters::G] = 0.; data.branch[0].parameters[BranchParameters::B] = 0.1; + data.branch[0].branch_type = BranchData::BranchType::LINE; // Branch 0-2 data.branch[1].ports[BranchPorts::bus1] = data.bus[0].bus_id; @@ -124,6 +125,7 @@ int main() data.branch[1].parameters[BranchParameters::X] = 0.15; data.branch[1].parameters[BranchParameters::G] = 0.; data.branch[1].parameters[BranchParameters::B] = 0.12; + data.branch[1].branch_type = BranchData::BranchType::LINE; // Branch 1-2 data.branch[2].ports[BranchPorts::bus1] = data.bus[1].bus_id; @@ -132,6 +134,7 @@ int main() data.branch[2].parameters[BranchParameters::X] = 0.27; data.branch[2].parameters[BranchParameters::G] = 0.; data.branch[2].parameters[BranchParameters::B] = 0.45; + data.branch[2].branch_type = BranchData::BranchType::LINE; // Set generator data data.genrou.resize(2); diff --git a/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp b/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp index 71fc02638..8cd2862b3 100644 --- a/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp +++ b/examples/PhasorDynamics/Tiny/ThreeBus/Classical/ThreeBusClassical.cpp @@ -117,6 +117,7 @@ int main() data.branch[0].parameters[BranchParameters::X] = 0.21; data.branch[0].parameters[BranchParameters::G] = 0.0; data.branch[0].parameters[BranchParameters::B] = 0.1; + data.branch[0].branch_type = BranchData::BranchType::LINE; // Branch 0-2 data.branch[1].ports[BranchPorts::bus1] = data.bus[0].bus_id; @@ -125,6 +126,7 @@ int main() data.branch[1].parameters[BranchParameters::X] = 0.15; data.branch[1].parameters[BranchParameters::G] = 0.0; data.branch[1].parameters[BranchParameters::B] = 0.12; + data.branch[1].branch_type = BranchData::BranchType::LINE; // Branch 1-2 data.branch[2].ports[BranchPorts::bus1] = data.bus[1].bus_id; @@ -133,6 +135,7 @@ int main() data.branch[2].parameters[BranchParameters::X] = 0.27; data.branch[2].parameters[BranchParameters::G] = 0.0; data.branch[2].parameters[BranchParameters::B] = 0.45; + data.branch[2].branch_type = BranchData::BranchType::LINE; // Set generator data data.genclassical.resize(2); diff --git a/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp b/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp index 43fe05c59..7e46891bd 100644 --- a/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp +++ b/examples/PhasorDynamics/Tiny/TwoBus/Basic/TwoBusBasic.cpp @@ -60,6 +60,7 @@ int main() data.branch[0].parameters[BranchParameters::X] = 0.1; data.branch[0].parameters[BranchParameters::G] = 0.0; data.branch[0].parameters[BranchParameters::B] = 0.0; + data.branch[0].branch_type = BranchData::BranchType::LINE; // Set generator data data.genrou.resize(1); diff --git a/examples/PhasorDynamics/Tiny/TwoBus/Ieeet1/TwoBusIeeet1.cpp b/examples/PhasorDynamics/Tiny/TwoBus/Ieeet1/TwoBusIeeet1.cpp index 392a80dc6..6a4590345 100644 --- a/examples/PhasorDynamics/Tiny/TwoBus/Ieeet1/TwoBusIeeet1.cpp +++ b/examples/PhasorDynamics/Tiny/TwoBus/Ieeet1/TwoBusIeeet1.cpp @@ -71,6 +71,7 @@ int main() data.branch[0].parameters[BranchParameters::X] = 0.1; data.branch[0].parameters[BranchParameters::G] = 0.0; data.branch[0].parameters[BranchParameters::B] = 0.0; + data.branch[0].branch_type = BranchData::BranchType::LINE; // Add faults data.bus_fault.resize(1); diff --git a/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp b/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp index b50164656..28cf44c29 100644 --- a/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp +++ b/examples/PhasorDynamics/Tiny/TwoBus/Tgov1/TwoBusTgov1.cpp @@ -70,6 +70,7 @@ int main() data.branch[0].parameters[BranchParameters::X] = 0.1; data.branch[0].parameters[BranchParameters::G] = 0.0; data.branch[0].parameters[BranchParameters::B] = 0.0; + data.branch[0].branch_type = BranchData::BranchType::LINE; // Add faults data.bus_fault.resize(1); diff --git a/tests/UnitTests/PhasorDynamics/BranchTests.hpp b/tests/UnitTests/PhasorDynamics/BranchTests.hpp index 167bce0a7..e0811e2d2 100644 --- a/tests/UnitTests/PhasorDynamics/BranchTests.hpp +++ b/tests/UnitTests/PhasorDynamics/BranchTests.hpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include @@ -71,10 +73,10 @@ namespace GridKit branch.allocate(); branch.evaluateResidual(); - success *= isEqual(bus1.Ir(), Ir1); - success *= isEqual(bus1.Ii(), Ii1); - success *= isEqual(bus2.Ir(), Ir2); - success *= isEqual(bus2.Ii(), Ii2); + success *= isEqual(bus1.i(0), Ir1); + success *= isEqual(bus1.i(1), Ii1); + success *= isEqual(bus2.i(0), Ir2); + success *= isEqual(bus2.i(1), Ii2); return success.report(__func__); } @@ -106,7 +108,7 @@ namespace GridKit branch.evaluateResidual(); ///< Computes the residual and the Jacobian values by tracking ///< the dependencies - std::vector residuals{bus1.Ir(), bus1.Ii(), bus2.Ir(), bus2.Ii()}; + std::vector residuals{bus1.i(0), bus1.i(1), bus2.i(0), bus2.i(1)}; std::vector ref = analyticalJacobian(R, X, G, B); /// Compare dependencies computed automatically to the ones computed analytically @@ -156,14 +158,14 @@ namespace GridKit branch.setR(R); bus1.evaluateResidual(); // <- set Ir1 to zero branch.evaluateResidual(); - success *= isEqual(bus1.Ir(), res_R); + success *= isEqual(bus1.i(0), res_R); branch.setR(zero); // Test setting branch series reactance branch.setX(X); bus1.evaluateResidual(); // <- set Ir1 to zero branch.evaluateResidual(); - success *= isEqual(bus1.Ir(), res_X); + success *= isEqual(bus1.i(0), res_X); branch.setX(zero); return success.report(__func__); @@ -171,19 +173,50 @@ namespace GridKit branch.setG(G); bus1.evaluateResidual(); // <- set Ir1 to zero branch.evaluateResidual(); - success *= isEqual(bus1.Ir(), res_G); + success *= isEqual(bus1.i(0), res_G); branch.setG(zero); // Test setting branch shunt charging branch.setB(B); bus1.evaluateResidual(); // <- set Ir1 to zero branch.evaluateResidual(); - success *= isEqual(bus1.Ir(), res_B); + success *= isEqual(bus1.i(0), res_B); branch.setB(zero); return success.report(__func__); } + TestOutcome verifyPortsThrowsOnNullPort() + { + TestStatus success = true; + + auto* bus1 = new PhasorDynamics::Bus(1.0, 0.0); + + PhasorDynamics::Branch* branch = + new PhasorDynamics::Branch(bus1, nullptr); + + bool threw = false; + std::string what_msg; + try + { + branch->allocate(); + } + catch (const std::runtime_error& e) + { + threw = true; + what_msg = e.what(); + } + + success *= threw; + success *= (what_msg.find("port 1") != std::string::npos); + success *= (what_msg.find("is null") != std::string::npos); + + delete branch; + delete bus1; + + return success.report(__func__); + } + private: std::vector analyticalJacobian(const RealT R, const RealT X, diff --git a/tests/UnitTests/PhasorDynamics/BusTests.hpp b/tests/UnitTests/PhasorDynamics/BusTests.hpp index 33ef90cf6..2631b1392 100644 --- a/tests/UnitTests/PhasorDynamics/BusTests.hpp +++ b/tests/UnitTests/PhasorDynamics/BusTests.hpp @@ -29,28 +29,28 @@ namespace GridKit // Create an infinite bus bus = new PhasorDynamics::BusInfinite(); - success *= isEqual(bus->Vr(), 0.0); - success *= isEqual(bus->Vi(), 0.0); + success *= isEqual(bus->v(0), 0.0); + success *= isEqual(bus->v(1), 0.0); delete bus; bus = new PhasorDynamics::BusInfinite(Vr, Vi); - success *= isEqual(bus->Vr(), Vr); - success *= isEqual(bus->Vi(), Vi); + success *= isEqual(bus->v(0), Vr); + success *= isEqual(bus->v(1), Vi); delete bus; // Create an default bus bus = new PhasorDynamics::Bus(); bus->allocate(); bus->initialize(); - success *= isEqual(bus->Vr(), 0.0); - success *= isEqual(bus->Vi(), 0.0); + success *= isEqual(bus->v(0), 0.0); + success *= isEqual(bus->v(1), 0.0); delete bus; bus = new PhasorDynamics::Bus(Vr, Vi); bus->allocate(); bus->initialize(); - success *= isEqual(bus->Vr(), Vr); - success *= isEqual(bus->Vi(), Vi); + success *= isEqual(bus->v(0), Vr); + success *= isEqual(bus->v(1), Vi); delete bus; bus = nullptr; @@ -69,29 +69,29 @@ namespace GridKit ScalarT Ii{2.0}; PhasorDynamics::BusInfinite bus_inf; - bus_inf.Ir() = Ir; - success *= isEqual(bus_inf.Ir(), Ir); - bus_inf.Ii() = Ii; - success *= isEqual(bus_inf.Ii(), Ii); + bus_inf.i(0) = Ir; + success *= isEqual(bus_inf.i(0), Ir); + bus_inf.i(1) = Ii; + success *= isEqual(bus_inf.i(1), Ii); bus_inf.evaluateResidual(); - success *= isEqual(bus_inf.Ir(), 0.0); - success *= isEqual(bus_inf.Ii(), 0.0); + success *= isEqual(bus_inf.i(0), 0.0); + success *= isEqual(bus_inf.i(1), 0.0); PhasorDynamics::Bus bus(Vr, Vi); bus.allocate(); bus.initialize(); - success *= isEqual(bus.Vr(), Vr); - success *= isEqual(bus.Vi(), Vi); + success *= isEqual(bus.v(0), Vr); + success *= isEqual(bus.v(1), Vi); - bus.Ir() = Ir; - success *= isEqual(bus.Ir(), Ir); - bus.Ii() = Ii; - success *= isEqual(bus.Ii(), Ii); + bus.i(0) = Ir; + success *= isEqual(bus.i(0), Ir); + bus.i(1) = Ii; + success *= isEqual(bus.i(1), Ii); bus.evaluateResidual(); - success *= isEqual(bus.Ir(), 0.0); - success *= isEqual(bus.Ii(), 0.0); + success *= isEqual(bus.i(0), 0.0); + success *= isEqual(bus.i(1), 0.0); return success.report(__func__); } diff --git a/tests/UnitTests/PhasorDynamics/LoadTests.hpp b/tests/UnitTests/PhasorDynamics/LoadTests.hpp index f8aae18ab..7d22953b6 100644 --- a/tests/UnitTests/PhasorDynamics/LoadTests.hpp +++ b/tests/UnitTests/PhasorDynamics/LoadTests.hpp @@ -64,8 +64,8 @@ namespace GridKit load.allocate(); load.evaluateResidual(); - success *= isEqual(bus.Ir(), Ir); - success *= isEqual(bus.Ii(), Ii); + success *= isEqual(bus.i(0), Ir); + success *= isEqual(bus.i(1), Ii); return success.report(__func__); } @@ -90,7 +90,7 @@ namespace GridKit load.evaluateResidual(); ///< Computes the residual and the Jacobian values by tracking ///< the dependencies - std::vector residuals{bus.Ir(), bus.Ii()}; + std::vector residuals{bus.i(0), bus.i(1)}; std::vector ref = analyticalJacobian(R, X); /// Compare dependencies computed automatically to the ones computed analytically diff --git a/tests/UnitTests/PhasorDynamics/LoadZIPTests.hpp b/tests/UnitTests/PhasorDynamics/LoadZIPTests.hpp index 15b68d535..eeb0d981e 100644 --- a/tests/UnitTests/PhasorDynamics/LoadZIPTests.hpp +++ b/tests/UnitTests/PhasorDynamics/LoadZIPTests.hpp @@ -71,13 +71,13 @@ namespace GridKit load.evaluateResidual(); - success *= isEqual(bus.Ir(), Ir); - success *= isEqual(bus.Ii(), Ii); + success *= isEqual(bus.i(0), Ir); + success *= isEqual(bus.i(1), Ii); - if (!isEqual(bus.Ir(), Ir) || !isEqual(bus.Ii(), Ii)) + if (!isEqual(bus.i(0), Ir) || !isEqual(bus.i(1), Ii)) { - std::cout << "Expected Ir: " << Ir << ", Obtained Ir: " << bus.Ir() << "\n"; - std::cout << "Expected Ii: " << Ii << ", Obtained Ii: " << bus.Ii() << "\n"; + std::cout << "Expected Ir: " << Ir << ", Obtained Ir: " << bus.i(0) << "\n"; + std::cout << "Expected Ii: " << Ii << ", Obtained Ii: " << bus.i(1) << "\n"; } return success.report(__func__); diff --git a/tests/UnitTests/PhasorDynamics/SystemTests.hpp b/tests/UnitTests/PhasorDynamics/SystemTests.hpp index 28d8f3299..493fea442 100644 --- a/tests/UnitTests/PhasorDynamics/SystemTests.hpp +++ b/tests/UnitTests/PhasorDynamics/SystemTests.hpp @@ -79,6 +79,7 @@ namespace GridKit data.branch[0].parameters[BranchParameters::X] = 4.0; data.branch[0].parameters[BranchParameters::G] = 0.2; data.branch[0].parameters[BranchParameters::B] = 1.2; + data.branch[0].branch_type = PhasorDynamics::BranchData::BranchType::LINE; // Create an empty system model system = new PhasorDynamics::SystemModel(data); @@ -95,10 +96,10 @@ namespace GridKit auto* bus0 = system->getBus(0); auto* bus1 = system->getBus(1); - success *= isEqual(bus0->Ir(), Ir0); - success *= isEqual(bus0->Ii(), Ii0); - success *= isEqual(bus1->Ir(), Ir1); - success *= isEqual(bus1->Ii(), Ii1); + success *= isEqual(bus0->i(0), Ir0); + success *= isEqual(bus0->i(1), Ii0); + success *= isEqual(bus1->i(0), Ir1); + success *= isEqual(bus1->i(1), Ii1); delete system; system = nullptr; @@ -143,10 +144,10 @@ namespace GridKit system.initialize(); system.evaluateResidual(); - success *= isEqual(bus1.Ir(), Ir1); - success *= isEqual(bus1.Ii(), Ii1); - success *= isEqual(bus2.Ir(), Ir2); - success *= isEqual(bus2.Ii(), Ii2); + success *= isEqual(bus1.i(0), Ir1); + success *= isEqual(bus1.i(1), Ii1); + success *= isEqual(bus2.i(0), Ir2); + success *= isEqual(bus2.i(1), Ii2); return success.report(__func__); } @@ -202,6 +203,7 @@ namespace GridKit data.branch[0].parameters[BranchParameters::X] = 4.0; data.branch[0].parameters[BranchParameters::G] = 0.2; data.branch[0].parameters[BranchParameters::B] = 1.2; + data.branch[0].branch_type = PhasorDynamics::BranchData::BranchType::LINE; // Jacobian via DependencyTracking std::vector dependency_tracking_jacobian = DependencyTrackingJacobian(data); diff --git a/tests/UnitTests/PhasorDynamics/runBranchTests.cpp b/tests/UnitTests/PhasorDynamics/runBranchTests.cpp index 123f5d290..3f4cabd5c 100644 --- a/tests/UnitTests/PhasorDynamics/runBranchTests.cpp +++ b/tests/UnitTests/PhasorDynamics/runBranchTests.cpp @@ -12,6 +12,7 @@ int main() result += test.accessors(); result += test.residual(); result += test.jacobian(); + result += test.verifyPortsThrowsOnNullPort(); return result.summary(); }