diff --git a/GridKit/Model/PhasorDynamics/Component.hpp b/GridKit/Model/PhasorDynamics/Component.hpp index b488bbe7a..707902dfc 100644 --- a/GridKit/Model/PhasorDynamics/Component.hpp +++ b/GridKit/Model/PhasorDynamics/Component.hpp @@ -287,6 +287,23 @@ namespace GridKit } protected: + void setComponentBase(RealT va_component_base) + { + va_component_base_ = va_component_base; + } + + template + value_type toComponentBase(value_type value) const + { + return value * (va_system_base_ / va_component_base_); + } + + template + value_type toSystemBase(value_type value) const + { + return value * (va_component_base_ / va_system_base_); + } + /** * @brief Allocate this component's state and residual vectors. */ @@ -375,6 +392,7 @@ namespace GridKit RealT freq_system_base_{60.0}; RealT va_system_base_{100.0e6}; + RealT va_component_base_{0}; using NotImplementedError = GridKit::Utilities::NotImplementedError; diff --git a/GridKit/Model/PhasorDynamics/Controller/REECB/README.md b/GridKit/Model/PhasorDynamics/Controller/REECB/README.md index 14617aad2..44d93bbe7 100644 --- a/GridKit/Model/PhasorDynamics/Controller/REECB/README.md +++ b/GridKit/Model/PhasorDynamics/Controller/REECB/README.md @@ -10,9 +10,8 @@ inverter-coupled resource.[^wecc-reecb-specification] reference instead of a system-base reactive power. > [!WARNING] -> GridKit does not yet inherit `mva` from the associated REGCA model. Set it -> explicitly to the REGCA component base; omitting it falls back to the system -> base and is correct only when those bases match.[^reecb-mva-base] +> GridKit does not inherit `mva` from the associated REGCA model. Set `mva` +> to the REGCA component base.[^reecb-mva-base] > [!WARNING] > GridKit does not yet apply the associated generator's Governor Response Limits @@ -29,7 +28,7 @@ Figure 1: REECB electrical-control model. Figure courtesy of the Symbol | Units | JSON | Description | Default | Note ------------------------------------|-----------|----------|---------------------------------------------------------|---------------|----- -$S^\mathrm{base}$ | [MVA] | `mva` | REECB component power base | System base | Explicit values must be positive +$S^\mathrm{base}$ | [MVA] | `mva` | REECB component power base | Required | Must be positive $s_\mathrm{pf}$ | [boolean] | `PfFlag` | Power-factor control selector | `false` | `true` = power-factor control, `false` = reactive-power control $s_V$ | [boolean] | `VFlag` | Voltage-reference selector under $s_Q=1$ | `false` | `true` = cascaded Q-PI voltage command, `false` = direct external voltage reference $s_Q$ | [boolean] | `QFlag` | Reactive-path selector | `false` | `true` = Volt/VAr PI control, `false` = reactive-current lag @@ -60,9 +59,8 @@ $P^{\max}$ | [p.u.] | `Pmax` | Maximum active-powe $P^{\min}$ | [p.u.] | `Pmin` | Minimum active-power order | 0.0 | $I^{\max}$ | [p.u.] | `Imax` | Maximum converter current | 1.3 | -All parameters are optional. An omitted parameter starts from its listed -default; the time-constant floor below is then applied. Real-valued parameters -accept real or integer JSON values; selectors require Boolean JSON values. +Real-valued parameters accept real or integer JSON values; selectors require +Boolean JSON values. ### Parameter Validation @@ -70,7 +68,7 @@ Invalid REECB parameter sets are rejected by the following checks: ```math \begin{aligned} - S^\mathrm{base} &> 0,\quad \text{when provided} \\ + S^\mathrm{base} &> 0 \\ T_\mathrm{rv},T_\mathrm{p},T_\mathrm{iq},T_\mathrm{pord} &\ge 0 \\ V_\mathrm{dip} &< V_\mathrm{up} \\ D_1^\mathrm{db} &\le 0 \le D_2^\mathrm{db} \\ diff --git a/GridKit/Model/PhasorDynamics/Controller/REECB/Reecb.hpp b/GridKit/Model/PhasorDynamics/Controller/REECB/Reecb.hpp index 9188a0920..0a920f8e0 100644 --- a/GridKit/Model/PhasorDynamics/Controller/REECB/Reecb.hpp +++ b/GridKit/Model/PhasorDynamics/Controller/REECB/Reecb.hpp @@ -87,6 +87,7 @@ namespace GridKit using Component::residual_indices_; using Component::size_; using Component::tag_; + using Component::va_component_base_; using Component::va_system_base_; using Component::variable_indices_; using Component::wb_; @@ -189,13 +190,6 @@ namespace GridKit static RealT logOneMinusExp(RealT x); bool iclamp(RealT output, RealT lower, RealT upper, RealT& input) const; - RealT componentPowerBase() const; - - template - [[gnu::always_inline]] inline ValueT toComponentBase(ValueT value) const; - - template - ValueT toSystemBase(ValueT value) const; ScalarT& Vr(); ScalarT& Vi(); @@ -208,7 +202,6 @@ namespace GridKit BusT* bus_{nullptr}; // Input parameters - RealT mva_base_{0}; bool PfFlag_{false}; bool VFlag_{false}; bool QFlag_{false}; @@ -239,12 +232,10 @@ namespace GridKit RealT Pmin_{0}; RealT Imax_{1.3}; - bool mva_given_{false}; bool Vref0_given_{false}; IdxT parameter_error_count_{0}; // Derived parameters - RealT va_component_base_{0}; RealT pf_on_{0}; RealT pf_off_{1}; RealT q_on_{0}; diff --git a/GridKit/Model/PhasorDynamics/Controller/REECB/ReecbImpl.hpp b/GridKit/Model/PhasorDynamics/Controller/REECB/ReecbImpl.hpp index 6d39b88ec..7b0e56b98 100644 --- a/GridKit/Model/PhasorDynamics/Controller/REECB/ReecbImpl.hpp +++ b/GridKit/Model/PhasorDynamics/Controller/REECB/ReecbImpl.hpp @@ -46,10 +46,7 @@ namespace GridKit }; /** - * @brief Construct REECB with its documented parameter defaults - * - * The terminal bus is retained, the model is sized, and no monitor or - * signal connection is created. + * @brief Construct an unconfigured REECB controller * * @param[in] bus Terminal bus measured by the controller. */ @@ -181,21 +178,21 @@ namespace GridKit check(bus_ != nullptr, "terminal bus is required"); - const RealT component_power_base = componentPowerBase(); - const bool valid_component_base = std::isfinite(component_power_base) && component_power_base > ZERO; - const bool valid_system_base = std::isfinite(va_system_base_) && va_system_base_ > ZERO; + const bool valid_component_base = std::isfinite(va_component_base_) + && va_component_base_ > ZERO; + const bool valid_system_base = std::isfinite(va_system_base_) + && va_system_base_ > ZERO; check(valid_component_base, "component power base must be finite and positive"); check(valid_system_base, "system power base must be finite and positive"); if (valid_component_base && valid_system_base) { - const RealT system_to_component = va_system_base_ / component_power_base; - const RealT component_to_system = component_power_base / va_system_base_; - check( - std::isfinite(system_to_component) - && system_to_component > ZERO - && std::isfinite(component_to_system) - && component_to_system > ZERO, - "system/component power-base conversion ratios must be finite and positive"); + const RealT system_to_component = va_system_base_ / va_component_base_; + const RealT component_to_system = va_component_base_ / va_system_base_; + check(std::isfinite(system_to_component) + && system_to_component > ZERO + && std::isfinite(component_to_system) + && component_to_system > ZERO, + "system/component power-base conversion ratios must be finite and positive"); } check(std::isfinite(Trv_), "Trv must be finite"); @@ -365,16 +362,16 @@ namespace GridKit const RealT ipcmd0_system = static_cast(y[IPCMD]); const RealT iqcmd0_system = static_cast(y[IQCMD]); - const RealT ipcmd0 = toComponentBase(ipcmd0_system); - const RealT iqcmd0 = toComponentBase(iqcmd0_system); + const RealT ipcmd0 = this->toComponentBase(ipcmd0_system); + const RealT iqcmd0 = this->toComponentBase(iqcmd0_system); const RealT vr0 = static_cast(Vr()); const RealT vi0 = static_cast(Vi()); const RealT vt0 = std::sqrt(vr0 * vr0 + vi0 * vi0); const RealT vmeas0 = vt0; const RealT vmeas_safe0 = Math::max(vmeas0, VMEAS_MINIMUM); - RealT pe0_system = toSystemBase(ipcmd0 * vmeas_safe0); - RealT qgen0_system = toSystemBase(iqcmd0 * vmeas_safe0); + RealT pe0_system = this->toSystemBase(ipcmd0 * vmeas_safe0); + RealT qgen0_system = this->toSystemBase(iqcmd0 * vmeas_safe0); if (signals_.template isAttached()) { @@ -387,8 +384,8 @@ namespace GridKit signals_.template readExternalVariable()); } - const RealT pmeas0 = toComponentBase(pe0_system); - const RealT qgen0 = toComponentBase(qgen0_system); + const RealT pmeas0 = this->toComponentBase(pe0_system); + const RealT qgen0 = this->toComponentBase(qgen0_system); RealT vref0 = vmeas0; if (Vref0_given_) { @@ -492,7 +489,7 @@ namespace GridKit } const RealT pmin = std::min(Pmin_, pord0); const RealT pmax = std::max(Pmax_, pord0); - const RealT pref0_system = toSystemBase(pord0); + const RealT pref0_system = this->toSystemBase(pord0); RealT qtarget0 = ZERO; if (!QFlag_) @@ -533,8 +530,8 @@ namespace GridKit } else { - qext0_port = toSystemBase(qtarget0); - qref0 = toComponentBase(qext0_port); + qext0_port = this->toSystemBase(qtarget0); + qref0 = this->toComponentBase(qext0_port); } const RealT eq0 = Math::clamp(qref0, qmin, qmax) - qgen0; @@ -966,13 +963,13 @@ namespace GridKit const ScalarT vr = wb[0]; const ScalarT vi = wb[1]; - const ScalarT pe = toComponentBase(ws[PE]); - const ScalarT qgen = toComponentBase(ws[QGEN]); + const ScalarT pe = this->toComponentBase(ws[PE]); + const ScalarT qgen = this->toComponentBase(ws[QGEN]); const ScalarT extref = ws[QEXT]; const ScalarT pfaref = ws[PFAREF]; - const ScalarT pref = toComponentBase(ws[PREF]); - const ScalarT iqcmd = toComponentBase(iqcmd_system); - const ScalarT ipcmd = toComponentBase(ipcmd_system); + const ScalarT pref = this->toComponentBase(ws[PREF]); + const ScalarT iqcmd = this->toComponentBase(iqcmd_system); + const ScalarT ipcmd = this->toComponentBase(ipcmd_system); const ScalarT verr = Math::deadband2(Vref0_ - vmeas, dbd1_, dbd2_); const ScalarT q_pi_state = Kqp_ * eq + xpiq; @@ -988,7 +985,7 @@ namespace GridKit // The Volt/VAr channel is a system-base reactive power unless // direct-voltage mode selects it as a terminal-voltage reference, // which takes no power-base conversion. - const ScalarT qref_target = q_ref_on_ * (pf_on_ * pmeas * std::tan(pfaref) + pf_off_ * toComponentBase(extref)); + const ScalarT qref_target = q_ref_on_ * (pf_on_ * pmeas * std::tan(pfaref) + pf_off_ * this->toComponentBase(extref)); f[VMEAS] = -vmeas_dot + (vt - vmeas) / Trv_; f[PMEAS] = -pmeas_dot + (pe - pmeas) / Tp_; @@ -1317,8 +1314,8 @@ namespace GridKit /** * @brief Read parameters from model data * - * Omitted parameters retain their documented defaults. Loading errors - * are counted for verify() rather than thrown. + * Omitted optional parameters retain their documented defaults. Loading + * errors are counted for verify() rather than thrown. * * @param[in] data Parameters and monitored-variable selections. */ @@ -1328,10 +1325,19 @@ namespace GridKit using Params = typename ModelDataT::Parameters; parameter_error_count_ = 0; - mva_given_ = data.parameters.contains(Params::mva); Vref0_given_ = false; - loadRealParameter(data, Params::mva, mva_base_, "mva"); + if (data.parameters.contains(Params::mva)) + { + RealT mva{}; + loadRealParameter(data, Params::mva, mva, "mva"); + this->setComponentBase(mva * static_cast(1.0e6)); + } + else + { + Log::error() << "Reecb: missing required parameter 'mva'\n"; + ++parameter_error_count_; + } loadBooleanParameter(data, Params::PfFlag, PfFlag_, "PfFlag"); loadBooleanParameter(data, Params::VFlag, VFlag_, "VFlag"); loadBooleanParameter(data, Params::QFlag, QFlag_, "QFlag"); @@ -1404,9 +1410,9 @@ namespace GridKit /** * @brief Resolve parameter-derived constants and selector masks * - * Raises explicit controller lags in place, converts any supplied component - * rating, and resolves selector masks. Invalid lag inputs are - * recorded before replacement so verify() retains each error. + * Raises explicit controller lags in place and resolves selector masks. + * Invalid lag inputs are recorded before replacement so verify() retains + * each error. */ template void Reecb::setDerivedParameters() @@ -1425,8 +1431,6 @@ namespace GridKit &logTimeConstantWarning); } - va_component_base_ = mva_base_ * static_cast(1.0e6); - if (PfFlag_ && QFlag_) { Log::warning() << "Reecb: PfFlag and QFlag are both enabled; " @@ -1543,49 +1547,6 @@ namespace GridKit return std::isfinite(input); } - /** - * @brief Resolve the REECB component power base - * - * @return The supplied component base, or the system base when `mva` is omitted. - */ - template - typename Reecb::RealT - Reecb::componentPowerBase() const - { - if (mva_given_) - { - return va_component_base_; - } - return va_system_base_; - } - - /** - * @brief Convert a system-base power or current to REECB component base - * - * @param[in] value Quantity on the system base. - * @return The same quantity on the REECB component base. - */ - template - template - [[gnu::always_inline]] inline ValueT - Reecb::toComponentBase(ValueT value) const - { - return value * (va_system_base_ / componentPowerBase()); - } - - /** - * @brief Convert a component-base power or current to system base - * - * @param[in] value Quantity on the REECB component base. - * @return The same quantity on the system base. - */ - template - template - ValueT Reecb::toSystemBase(ValueT value) const - { - return value * (componentPowerBase() / va_system_base_); - } - /** * @brief Access the terminal-bus real voltage component * diff --git a/GridKit/Model/PhasorDynamics/Controller/REPCA/Repca.hpp b/GridKit/Model/PhasorDynamics/Controller/REPCA/Repca.hpp index e8607b45d..c64c7e1ce 100644 --- a/GridKit/Model/PhasorDynamics/Controller/REPCA/Repca.hpp +++ b/GridKit/Model/PhasorDynamics/Controller/REPCA/Repca.hpp @@ -92,6 +92,7 @@ namespace GridKit using Component::residual_indices_; using Component::size_; using Component::tag_; + using Component::va_component_base_; using Component::va_system_base_; using Component::variable_indices_; using Component::wb_; @@ -155,9 +156,6 @@ namespace GridKit static RealT logOneMinusExp(RealT x); - [[gnu::always_inline]] inline ScalarT toComponentBase(ScalarT value) const; - ScalarT toSystemBase(ScalarT value) const; - ScalarT& Vr(); ScalarT& Vi(); @@ -201,7 +199,6 @@ namespace GridKit RealT Tlag_{static_cast(3.0)}; IdxT parameter_error_count_{0}; - RealT va_component_base_{ZERO}; RealT vcomp_on_{ONE}; RealT vcomp_off_{ZERO}; RealT ref_on_{ONE}; diff --git a/GridKit/Model/PhasorDynamics/Controller/REPCA/RepcaImpl.hpp b/GridKit/Model/PhasorDynamics/Controller/REPCA/RepcaImpl.hpp index 8b504d7da..df00c444f 100644 --- a/GridKit/Model/PhasorDynamics/Controller/REPCA/RepcaImpl.hpp +++ b/GridKit/Model/PhasorDynamics/Controller/REPCA/RepcaImpl.hpp @@ -295,8 +295,8 @@ namespace GridKit const ScalarT qext0_system = y[QEXT]; const ScalarT pext0_system = y[PEXT]; - const ScalarT qext0 = toComponentBase(qext0_system); - const ScalarT pext0 = toComponentBase(pext0_system); + const ScalarT qext0 = this->toComponentBase(qext0_system); + const ScalarT pext0 = this->toComponentBase(pext0_system); const ScalarT vr = Vr(); const ScalarT vi = Vi(); @@ -308,8 +308,8 @@ namespace GridKit signals_.template readExternalVariable(); const ScalarT q_system = signals_.template readExternalVariable(); - const ScalarT ir = toComponentBase(ir_system); - const ScalarT ii = toComponentBase(ii_system); + const ScalarT ir = this->toComponentBase(ir_system); + const ScalarT ii = this->toComponentBase(ii_system); ScalarT freq = static_cast(ONE); if (signals_.template isAttached()) { @@ -329,8 +329,8 @@ namespace GridKit return 1; } - const ScalarT p = toComponentBase(p_system); - const ScalarT q = toComponentBase(q_system); + const ScalarT p = this->toComponentBase(p_system); + const ScalarT q = this->toComponentBase(q_system); const ScalarT vldc_r = vr - Rc_ * ir + Xc_ * ii; const ScalarT vldc_i = vi - Rc_ * ii - Xc_ * ir; @@ -418,9 +418,9 @@ namespace GridKit } else { - qref0_system = toSystemBase(qmeas0 + erq0); + qref0_system = this->toSystemBase(qmeas0 + erq0); } - const ScalarT pref0_system = p_system + toSystemBase(ep0 - pfreq0); + const ScalarT pref0_system = p_system + this->toSystemBase(ep0 - pfreq0); const bool candidates_are_finite = is_finite(qext0_system) @@ -785,12 +785,12 @@ namespace GridKit const ScalarT erqdb = y[ERQDB]; const ScalarT erqlim = y[ERQLIM]; const ScalarT qpi = y[QPI]; - const ScalarT qext = toComponentBase(y[QEXT]); + const ScalarT qext = this->toComponentBase(y[QEXT]); const ScalarT ef = y[EF]; const ScalarT ep = y[EP]; const ScalarT eplim = y[EPLIM]; const ScalarT ppi = y[PPI]; - const ScalarT pext = toComponentBase(y[PEXT]); + const ScalarT pext = this->toComponentBase(y[PEXT]); const ScalarT vmeas_dot = yp[VMEAS]; const ScalarT qmeas_dot = yp[QMEAS]; @@ -803,15 +803,15 @@ namespace GridKit const ScalarT vr = wb[0]; const ScalarT vi = wb[1]; - const ScalarT ir = toComponentBase(ws[IR]); - const ScalarT ii = toComponentBase(ws[II]); - const ScalarT p = toComponentBase(ws[P]); - const ScalarT q = toComponentBase(ws[Q]); + const ScalarT ir = this->toComponentBase(ws[IR]); + const ScalarT ii = this->toComponentBase(ws[II]); + const ScalarT p = this->toComponentBase(ws[P]); + const ScalarT q = this->toComponentBase(ws[Q]); const ScalarT freq = ws[FREQ]; const ScalarT freqref = ws[FREQREF]; const ScalarT vref = ws[VREF]; - const ScalarT qref = toComponentBase(ws[QREF]); - const ScalarT pref_in = toComponentBase(ws[PREF_INPUT]); + const ScalarT qref = this->toComponentBase(ws[QREF]); + const ScalarT pref_in = this->toComponentBase(ws[PREF_INPUT]); const ScalarT vldc_r = vr - Rc_ * ir + Xc_ * ii; const ScalarT vldc_i = vi - Rc_ * ii - Xc_ * ir; @@ -1042,7 +1042,7 @@ namespace GridKit Tp_ = std::max(Tp_, TIME_CONSTANT_MINIMUM); Tlag_ = std::max(Tlag_, TIME_CONSTANT_MINIMUM); - va_component_base_ = mva_base_ * static_cast(1.0e6); + this->setComponentBase(mva_base_ * static_cast(1.0e6)); vcomp_on_ = VcompFlag_ ? ONE : ZERO; vcomp_off_ = ONE - vcomp_on_; @@ -1208,31 +1208,6 @@ namespace GridKit return std::log1p(-std::exp(-x)); } - /** - * @brief Convert a system-base power or current quantity to REPCA component base - * - * @param[in] value Quantity on the system base. - * @return The same quantity on the REPCA component base. - */ - template - [[gnu::always_inline]] inline scalar_type - Repca::toComponentBase(scalar_type value) const - { - return value * (va_system_base_ / va_component_base_); - } - - /** - * @brief Convert a component-base power quantity to system base - * - * @param[in] value Quantity on the REPCA component base. - * @return The same quantity on the system base. - */ - template - scalar_type Repca::toSystemBase(scalar_type value) const - { - return value * (va_component_base_ / va_system_base_); - } - /** * @brief Access the regulated-bus real voltage component * diff --git a/GridKit/Model/PhasorDynamics/Converter/REGCA/Regca.hpp b/GridKit/Model/PhasorDynamics/Converter/REGCA/Regca.hpp index 0ce153803..c360c94cc 100644 --- a/GridKit/Model/PhasorDynamics/Converter/REGCA/Regca.hpp +++ b/GridKit/Model/PhasorDynamics/Converter/REGCA/Regca.hpp @@ -79,7 +79,6 @@ namespace GridKit using Component::residual_indices_; using Component::size_; using Component::tag_; - using Component::va_system_base_; using Component::variable_indices_; using Component::wb_; using Component::ws_; @@ -133,9 +132,6 @@ namespace GridKit void initializeMonitor(); void setDerivedParameters(); - ScalarT toComponentBase(ScalarT value) const; - ScalarT toSystemBase(ScalarT value) const; - /** * @brief Smooth approximation of the REGCA `rrpwr` rate limiter. * @@ -228,7 +224,6 @@ namespace GridKit IdxT parameter_error_count_{0}; // Derived parameters - RealT va_converter_base_{0}; RealT use_lvpl_{0}; RealT bypass_lvpl_{1}; RealT use_rqmax_{0}; diff --git a/GridKit/Model/PhasorDynamics/Converter/REGCA/RegcaImpl.hpp b/GridKit/Model/PhasorDynamics/Converter/REGCA/RegcaImpl.hpp index 1fad805c1..11159267e 100644 --- a/GridKit/Model/PhasorDynamics/Converter/REGCA/RegcaImpl.hpp +++ b/GridKit/Model/PhasorDynamics/Converter/REGCA/RegcaImpl.hpp @@ -114,31 +114,7 @@ namespace GridKit use_rqmin_ = ONE; } - va_converter_base_ = mva_base_ * static_cast(1.0e6); - } - - /** - * @brief Convert a system-base per-unit value to the component base. - * - * @param[in] value Value on the system base. - * @return Value on the REGCA component base. - */ - template - scalar_type Regca::toComponentBase(scalar_type value) const - { - return value * va_system_base_ / va_converter_base_; - } - - /** - * @brief Convert a component-base per-unit value to the system base. - * - * @param[in] value Value on the REGCA component base. - * @return Value on the system base. - */ - template - scalar_type Regca::toSystemBase(scalar_type value) const - { - return value / toComponentBase(static_cast(ONE)); + this->setComponentBase(mva_base_ * static_cast(1.0e6)); } /** @@ -493,7 +469,7 @@ namespace GridKit // P0 is a system-base power-flow injection. Resolve the component-base // active current through the LVACM network-interface gain. const ScalarT lvacm = Math::linseg(vt, VA0_, VA1_, ONE); - const ScalarT ip0 = toComponentBase(static_cast(p0_) / vt) / lvacm; + const ScalarT ip0 = this->toComponentBase(static_cast(p0_) / vt) / lvacm; const ScalarT il0 = Math::linseg(vt, VL0_, VL1_, IL1_) + KL_ * Math::ramp(vt - VL1_); @@ -506,7 +482,7 @@ namespace GridKit // Evaluate the HVRCM law and preserve the requested Q0. const ScalarT iqextra0 = Khv_ * Math::ramp(vt - Vhvmax_); - const ScalarT qnet0 = toComponentBase(static_cast(q0_) / vt); + const ScalarT qnet0 = this->toComponentBase(static_cast(q0_) / vt); const ScalarT iqcmd0 = qnet0 + iqextra0; const ScalarT ir0 = (vi * qnet0 + vr * ip0 * lvacm) / vt; const ScalarT ii0 = (-vr * qnet0 + vi * ip0 * lvacm) / vt; @@ -517,13 +493,13 @@ namespace GridKit y[IQ] = iqcmd0; y[IQEXTRA] = iqextra0; y[IL] = il0; - y[IR] = toSystemBase(ir0); - y[II] = toSystemBase(ii0); + y[IR] = this->toSystemBase(ir0); + y[II] = this->toSystemBase(ii0); y[PBR] = vr * y[IR] + vi * y[II]; y[QBR] = vi * y[IR] - vr * y[II]; - ipcmd_set_ = toSystemBase(ipcmd0); - iqcmd_set_ = toSystemBase(iqcmd0); + ipcmd_set_ = this->toSystemBase(ipcmd0); + iqcmd_set_ = this->toSystemBase(iqcmd0); // Publish the resolved system-base commands for downstream controller // initialization. Unattached ports retain these values as constant @@ -621,8 +597,8 @@ namespace GridKit const ScalarT vr = wb[0]; const ScalarT vi = wb[1]; - const ScalarT ipcmd = toComponentBase(ws[IPCMD]); - const ScalarT iqcmd = toComponentBase(ws[IQCMD]); + const ScalarT ipcmd = this->toComponentBase(ws[IPCMD]); + const ScalarT iqcmd = this->toComponentBase(ws[IQCMD]); // Form the unconstrained current derivatives, then apply the REGCA // recovery rate limits in p.u./s. @@ -649,8 +625,8 @@ namespace GridKit f[IP] = -ip_dot + bypass_lvpl_ * fp_limited + use_lvpl_ * awmax(ip, fp_limited, il, il_rate); f[VT] = -vt * vt + vr * vr + vi * vi; - f[IR] = -toComponentBase(vt * ir) + vi * qnet + vr * ip * lvacm; - f[II] = -toComponentBase(vt * ii) - vr * qnet + vi * ip * lvacm; + f[IR] = -this->toComponentBase(vt * ir) + vi * qnet + vr * ip * lvacm; + f[II] = -this->toComponentBase(vt * ii) - vr * qnet + vi * ip * lvacm; f[IQEXTRA] = -iqextra + Khv_ * Math::ramp(vt - Vhvmax_); f[IL] = -il + Math::linseg(vm, VL0_, VL1_, IL1_) + KL_ * Math::ramp(vm - VL1_); diff --git a/GridKit/Model/PhasorDynamics/Governor/GASTPTI/GastPti.hpp b/GridKit/Model/PhasorDynamics/Governor/GASTPTI/GastPti.hpp index f9f9819eb..a2cffa222 100644 --- a/GridKit/Model/PhasorDynamics/Governor/GASTPTI/GastPti.hpp +++ b/GridKit/Model/PhasorDynamics/Governor/GASTPTI/GastPti.hpp @@ -63,6 +63,7 @@ namespace GridKit using Component::residual_indices_; using Component::size_; using Component::tag_; + using Component::va_component_base_; using Component::va_system_base_; using Component::variable_indices_; using Component::wb_; @@ -118,9 +119,7 @@ namespace GridKit void initializeMonitor(); void setDerivedParameters(); - static RealT iramp(RealT value); - [[gnu::always_inline]] inline scalar_type toComponentBase(scalar_type value) const; - RealT toSystemBase(RealT value) const; + static RealT iramp(RealT value); static constexpr RealT TIME_CONSTANT_MINIMUM = static_cast(1.0e-3); static void logTimeConstantWarning(); @@ -134,16 +133,11 @@ namespace GridKit RealT Vmax_{ONE}; RealT Vmin_{ZERO}; RealT Dturb_{ZERO}; - RealT Trate_{ZERO}; - - RealT va_component_base_{ZERO}; RealT Vmin_response_{ZERO}; RealT Vmax_response_{ONE}; RealT s_valve_{ONE}; - IdxT parameter_error_count_{0}; - bool trate_provided_{false}; - + IdxT parameter_error_count_{0}; ScalarT pref_set_{0}; ComponentSignals signals_; diff --git a/GridKit/Model/PhasorDynamics/Governor/GASTPTI/GastPtiData.hpp b/GridKit/Model/PhasorDynamics/Governor/GASTPTI/GastPtiData.hpp index 14c29c74f..6307bd03c 100644 --- a/GridKit/Model/PhasorDynamics/Governor/GASTPTI/GastPtiData.hpp +++ b/GridKit/Model/PhasorDynamics/Governor/GASTPTI/GastPtiData.hpp @@ -26,7 +26,7 @@ namespace GridKit Vmax, ///< \f$V^{\max}\f$ Configured upper valve limit on component base [p.u.] Vmin, ///< \f$V^{\min}\f$ Configured lower valve limit on component base [p.u.] Dturb, ///< \f$D^\mathrm{turb}\f$ Component-base power per speed deviation [p.u.] - Trate ///< \f$T^\mathrm{rate}\f$ Optional MW rating defining the component base; system base if omitted [MW] + Trate ///< \f$T^\mathrm{rate}\f$ MW rating defining the component base [MW] }; /// Buses for the GASTPTI governor model. diff --git a/GridKit/Model/PhasorDynamics/Governor/GASTPTI/GastPtiImpl.hpp b/GridKit/Model/PhasorDynamics/Governor/GASTPTI/GastPtiImpl.hpp index 04b10dbeb..a4d87108a 100644 --- a/GridKit/Model/PhasorDynamics/Governor/GASTPTI/GastPtiImpl.hpp +++ b/GridKit/Model/PhasorDynamics/Governor/GASTPTI/GastPtiImpl.hpp @@ -28,12 +28,7 @@ namespace GridKit using Log = ::GridKit::Utilities::Logger; /** - * @brief Construct a GASTPTI governor without parameters - * - * The model is sized and every parameter keeps its documented default. - * No monitor or mechanical-power output assignment is created, so - * getMonitor() returns nullptr and verify() rejects the model until the - * containing system assigns `pmech`. + * @brief Construct an unconfigured GASTPTI governor */ template GastPti::GastPti() @@ -167,23 +162,17 @@ namespace GridKit check(std::isfinite(Dturb_) && Dturb_ >= ZERO, "Dturb must be finite and non-negative"); - const RealT component_power_base = trate_provided_ ? va_component_base_ : va_system_base_; - const bool valid_component_base = std::isfinite(component_power_base) - && component_power_base > ZERO; - const bool valid_system_base = - std::isfinite(va_system_base_) && va_system_base_ > ZERO; - if (trate_provided_) - { - check(std::isfinite(Trate_) && Trate_ > ZERO - && valid_component_base, - "Trate must define a finite positive component power base"); - } + const bool valid_component_base = std::isfinite(va_component_base_) + && va_component_base_ > ZERO; + const bool valid_system_base = std::isfinite(va_system_base_) + && va_system_base_ > ZERO; + check(valid_component_base, "component power base must be finite and positive"); check(valid_system_base, "system power base must be finite and positive"); if (valid_component_base && valid_system_base) { - const RealT system_to_component = va_system_base_ / component_power_base; - const RealT component_to_system = component_power_base / va_system_base_; + const RealT system_to_component = va_system_base_ / va_component_base_; + const RealT component_to_system = va_component_base_ / va_system_base_; check(std::isfinite(system_to_component) && system_to_component > ZERO && std::isfinite(component_to_system) @@ -294,11 +283,6 @@ namespace GridKit return 1; } - if (!trate_provided_) - { - va_component_base_ = va_system_base_; - } - auto* y = y_.getData(); const ScalarT pmech_system0 = y[PMECH]; if (!std::isfinite(static_cast(pmech_system0))) @@ -319,7 +303,7 @@ namespace GridKit return 1; } - const ScalarT pmech0 = toComponentBase(pmech_system0); + const ScalarT pmech0 = this->toComponentBase(pmech_system0); const RealT pmech0_value = static_cast(pmech0); const RealT xflow0 = pmech0_value + Dturb_ * omega0; const RealT vtemp0 = At_ + Kt_ * (At_ - xflow0); @@ -373,7 +357,7 @@ namespace GridKit } const RealT pref_component0 = vload0 + omega0 / R_; - const RealT pref0 = toSystemBase(pref_component0); + const RealT pref0 = this->toSystemBase(pref_component0); if (!std::isfinite(vload0) || !std::isfinite(vlv0) || !std::isfinite(pref_component0) || !std::isfinite(pref0)) { @@ -568,7 +552,7 @@ namespace GridKit const ScalarT xtemp_dot = yp[XTEMP]; const ScalarT omega = ws[OMEGA]; - const ScalarT pref = toComponentBase(ws[PREF]); + const ScalarT pref = this->toComponentBase(ws[PREF]); const ScalarT valve_target = Math::antiwindup(xvalve, vlv - xvalve, Vmin_response_, Vmax_response_); @@ -579,7 +563,7 @@ namespace GridKit f[VLOAD] = -omega + R_ * (pref - vload); f[VTEMP] = -vtemp + At_ + Kt_ * (At_ - xtemp); f[VLV] = -vlv + Math::min(vload, vtemp); - f[PMECH] = -toComponentBase(pmech) + xflow - Dturb_ * omega; + f[PMECH] = -this->toComponentBase(pmech) + xflow - Dturb_ * omega; return 0; } @@ -659,10 +643,8 @@ namespace GridKit /** * @brief Read the parameters out of the model data * - * Every parameter is optional and keeps the default documented in the - * model README when omitted. A non-numeric value is counted and reported - * by verify() rather than throwing. Integer JSON values are accepted for - * real parameters. + * Omitted optional parameters retain their documented defaults. Loading + * errors are counted for verify() rather than thrown. * * @param[in] data Parameters and monitored-variable selections. */ @@ -672,7 +654,6 @@ namespace GridKit using Params = typename ModelDataT::Parameters; parameter_error_count_ = 0; - trate_provided_ = data.parameters.contains(Params::Trate); loadRealParameter(data, Params::R, R_, "R"); loadRealParameter(data, Params::T1, T1_, "T1"); @@ -683,7 +664,17 @@ namespace GridKit loadRealParameter(data, Params::Vmax, Vmax_, "Vmax"); loadRealParameter(data, Params::Vmin, Vmin_, "Vmin"); loadRealParameter(data, Params::Dturb, Dturb_, "Dturb"); - loadRealParameter(data, Params::Trate, Trate_, "Trate"); + if (data.parameters.contains(Params::Trate)) + { + RealT trate{}; + loadRealParameter(data, Params::Trate, trate, "Trate"); + this->setComponentBase(trate * static_cast(1.0e6)); + } + else + { + Log::error() << "GastPti: missing required parameter 'Trate'\n"; + ++parameter_error_count_; + } setDerivedParameters(); } @@ -732,11 +723,9 @@ namespace GridKit * @brief Resolve the parameter-derived constants * * Validates and raises each turbine lag in place so every explicit - * differential row retains a nonzero denominator, sizes the component - * power base from a supplied turbine rating, and resets the parameter-only - * response defaults. An omitted rating is resolved from the current system - * base during initialize(). That method transactionally finalizes the - * operating-point-dependent response bounds and valve mask. + * differential row retains a nonzero denominator and resets the + * parameter-only response defaults. initialize() transactionally + * finalizes the operating-point-dependent response bounds and valve mask. * Recording invalid lag inputs before the in-place floor preserves the * loading error for verify(). */ @@ -756,11 +745,6 @@ namespace GridKit &logTimeConstantWarning); } - va_component_base_ = ZERO; - if (trate_provided_) - { - va_component_base_ = Trate_ * static_cast(1.0e6); - } Vmin_response_ = Vmin_; Vmax_response_ = Vmax_; @@ -787,31 +771,6 @@ namespace GridKit return value + std::log(-std::expm1(-mu * value)) / mu; } - /** - * @brief Convert a system-base power to GASTPTI component base - * - * @param[in] value Quantity on the system base. - * @return The same quantity on the component base. - */ - template - [[gnu::always_inline]] inline scalar_type - GastPti::toComponentBase(scalar_type value) const - { - return value * (va_system_base_ / va_component_base_); - } - - /** - * @brief Convert a component-base power to the system base - * - * @param[in] value Quantity on the component base. - * @return The same quantity on the system base. - */ - template - auto GastPti::toSystemBase(RealT value) const -> RealT - { - return value * (va_component_base_ / va_system_base_); - } - } // namespace Governor } // namespace PhasorDynamics } // namespace GridKit diff --git a/GridKit/Model/PhasorDynamics/Governor/GASTPTI/README.md b/GridKit/Model/PhasorDynamics/Governor/GASTPTI/README.md index f4f7c9110..d5696627a 100644 --- a/GridKit/Model/PhasorDynamics/Governor/GASTPTI/README.md +++ b/GridKit/Model/PhasorDynamics/Governor/GASTPTI/README.md @@ -35,7 +35,7 @@ $K_T$ | [p.u.] | `Kt` | Exhaust-temperature feedback gain $V^{\max}$ | [p.u.] | `Vmax` | Upper valve response limit | 1.0 | Component base $V^{\min}$ | [p.u.] | `Vmin` | Lower valve response limit | 0.0 | Component base $D^\mathrm{turb}$ | [p.u.] | `Dturb` | Turbine damping coefficient | 0.0 | Component-base power per speed deviation -$T^\mathrm{rate}$ | [MW] | `Trate` | Turbine rating | System base | Same-valued MVA component base when provided; GridKit addition +$T^\mathrm{rate}$ | [MW] | `Trate` | Turbine rating | Required | Same-valued MVA component base; GridKit addition ### Parameter Validation @@ -45,7 +45,7 @@ $T^\mathrm{rate}$ | [MW] | `Trate` | Turbine rating R &> 0 \\ T_1,T_2,T_3 &\ge 0 \\ A_T,K_T,D^\mathrm{turb} &\ge 0 \\ - T^\mathrm{rate} &> 0 \quad \text{when provided} \\ + T^\mathrm{rate} &> 0 \\ V^{\min} &\le V^{\max} \end{aligned} ``` @@ -60,11 +60,7 @@ $\epsilon_T$ are raised to that floor in place: T_x &\leftarrow \max\!\left(T_x,\epsilon_T\right), && x\in\{1,2,3\} \\ S^{\mathrm{base}} - &\leftarrow - \begin{cases} - 10^6 T^\mathrm{rate} & T^\mathrm{rate}\text{ provided} \\ - S^{\mathrm{sys}} & T^\mathrm{rate}\text{ omitted} - \end{cases} \\ + &\leftarrow 10^6 T^\mathrm{rate} \\ k_{\mathrm{base}} &= \dfrac{S^{\mathrm{sys}}}{S^{\mathrm{base}}} \end{aligned} diff --git a/GridKit/Model/PhasorDynamics/Governor/HYGOV/Hygov.hpp b/GridKit/Model/PhasorDynamics/Governor/HYGOV/Hygov.hpp index 9dd3118c9..14b2f11eb 100644 --- a/GridKit/Model/PhasorDynamics/Governor/HYGOV/Hygov.hpp +++ b/GridKit/Model/PhasorDynamics/Governor/HYGOV/Hygov.hpp @@ -74,6 +74,7 @@ namespace GridKit using Component::residual_indices_; using Component::size_; using Component::tag_; + using Component::va_component_base_; using Component::va_system_base_; using Component::variable_indices_; using Component::wb_; @@ -149,9 +150,6 @@ namespace GridKit /// Solve the dam head that reproduces mechanical power at Gv5. RealT solveInitialDamHead(RealT pmech) const; - ScalarT toComponentBase(ScalarT value) const; - ScalarT toSystemBase(ScalarT value) const; - static constexpr RealT TIME_CONSTANT_MINIMUM = static_cast(1.0e-3); static void logTimeConstantWarning(); @@ -179,11 +177,9 @@ namespace GridKit std::array Gv_{}; std::array Pgv_{}; - RealT va_component_base_{ZERO}; RealT leadlag_gain_{ZERO}; - IdxT parameter_error_count_{0}; - + IdxT parameter_error_count_{0}; RealT Gmin_response_{Gmin_}; RealT Gmax_response_{Gmax_}; RealT Hdam_eff_{Hdam_}; diff --git a/GridKit/Model/PhasorDynamics/Governor/HYGOV/HygovImpl.hpp b/GridKit/Model/PhasorDynamics/Governor/HYGOV/HygovImpl.hpp index 21c5de903..9336bc730 100644 --- a/GridKit/Model/PhasorDynamics/Governor/HYGOV/HygovImpl.hpp +++ b/GridKit/Model/PhasorDynamics/Governor/HYGOV/HygovImpl.hpp @@ -28,10 +28,7 @@ namespace GridKit using Log = ::GridKit::Utilities::Logger; /** - * @brief Construct a HYGOV governor without parameters - * - * The model is sized with the documented parameter defaults but without - * a monitor or assigned mechanical-power output. + * @brief Construct an unconfigured HYGOV governor */ template Hygov::Hygov() @@ -146,16 +143,8 @@ namespace GridKit } }; - RealT component_power_base = va_component_base_; - const bool component_base_is_omitted = - !(component_power_base > ZERO); - if (component_base_is_omitted) - { - component_power_base = va_system_base_; - } - - const bool valid_component_base = std::isfinite(component_power_base) - && component_power_base > ZERO; + const bool valid_component_base = std::isfinite(va_component_base_) + && va_component_base_ > ZERO; const bool valid_system_base = std::isfinite(va_system_base_) && va_system_base_ > ZERO; check(valid_component_base, @@ -164,8 +153,8 @@ namespace GridKit "system power base must be finite and positive"); if (valid_component_base && valid_system_base) { - const RealT system_to_component = va_system_base_ / component_power_base; - const RealT component_to_system = component_power_base / va_system_base_; + const RealT system_to_component = va_system_base_ / va_component_base_; + const RealT component_to_system = va_component_base_ / va_system_base_; const bool valid_base_ratios = std::isfinite(system_to_component) && system_to_component > ZERO && std::isfinite(component_to_system) @@ -296,12 +285,6 @@ namespace GridKit return 1; } - ret = va_component_base_ > ZERO; - if (!ret) - { - va_component_base_ = va_system_base_; - } - auto* y = y_.getData(); // The assigned pmech node aliases this entry after allocate(). Its @@ -333,8 +316,8 @@ namespace GridKit return 1; } - const ScalarT pmech0 = toComponentBase(pmech0_system); - const ScalarT paux0 = toComponentBase(paux0_system); + const ScalarT pmech0 = this->toComponentBase(pmech0_system); + const ScalarT paux0 = this->toComponentBase(paux0_system); ret = is_finite(pmech0) && is_finite(paux0); if (!ret) @@ -389,7 +372,7 @@ namespace GridKit const ScalarT omegadb0 = Math::deadband1(omega0, -db1_, db1_); const ScalarT xn0 = omegadb0; const ScalarT yomega0 = xn0 + leadlag_gain_ * (omegadb0 - xn0); - const ScalarT pref0 = toSystemBase(yomega0 + Rperm_ * gate0 - paux0); + const ScalarT pref0 = this->toSystemBase(yomega0 + Rperm_ * gate0 - paux0); ret = is_finite(h0) && is_finite(pgv0) @@ -624,12 +607,12 @@ namespace GridKit f[G] = -g_dot + (c - g) / Tg_; f[Q] = -q_dot + (Hdam_eff_ - head) / Tw_; f[OMEGADB] = -omegadb + Math::deadband1(omega, -db1_, db1_); - f[EF] = -ef + toComponentBase(pref + paux) - yomega - Rperm_ * c; + f[EF] = -ef + this->toComponentBase(pref + paux) - yomega - Rperm_ * c; f[FC] = -Rtemp_ * fc + xf / Tr_ + (ef - xf) / Tf_; f[RC] = -rc + Math::clamp(fc, -Velm_, Velm_); f[PGV] = -pgv + gatePower(g); f[H] = -q * q + head * pgv * pgv; - f[PMECH] = -toComponentBase(pmech) + At_ * head * (q - Qnl_) - Dturb_ * omega * g; + f[PMECH] = -this->toComponentBase(pmech) + At_ * head * (q - Qnl_) - Dturb_ * omega * g; return 0; } @@ -641,11 +624,9 @@ namespace GridKit /** * @brief Read the parameters out of the model data * - * Every omitted parameter keeps the default documented in the model - * README. A non-numeric or nonfinite value is counted and reported by - * verify() rather than throwing. Integer JSON values are accepted for - * real parameters. All-zero `Gv` and `Pgv` source points select the - * identity gate curve. + * Omitted optional parameters retain their documented defaults. Loading + * errors are counted for verify() rather than thrown. All-zero `Gv` and + * `Pgv` source points select the identity gate curve. * * @param[in] data Parameters and monitored-variable selections. */ @@ -692,16 +673,18 @@ namespace GridKit return true; }; - bool ret = load_real(Params::Trate, va_component_base_, "Trate"); - if (ret) + if (data.parameters.contains(Params::Trate)) { - ret = va_component_base_ > ZERO; - if (!ret) + RealT trate{}; + if (load_real(Params::Trate, trate, "Trate")) { - Log::error() << "Hygov: Trate must be positive when provided\n"; - ++parameter_error_count_; + this->setComponentBase(trate * static_cast(1.0e6)); } - va_component_base_ *= static_cast(1.0e6); + } + else + { + Log::error() << "Hygov: missing required parameter 'Trate'\n"; + ++parameter_error_count_; } load_real(Params::Rperm, Rperm_, "Rperm"); load_real(Params::Rtemp, Rtemp_, "Rtemp"); @@ -1076,30 +1059,6 @@ namespace GridKit return bisectInitialRoot(a, b, fa, fb, residual); } - /** - * @brief Convert a system-base power to HYGOV component base - * - * @param[in] value Quantity on the system base. - * @return The same quantity on the component base. - */ - template - scalar_type Hygov::toComponentBase(scalar_type value) const - { - return value * va_system_base_ / va_component_base_; - } - - /** - * @brief Convert a component-base power to the system base - * - * @param[in] value Quantity on the component base. - * @return The same quantity on the system base. - */ - template - scalar_type Hygov::toSystemBase(scalar_type value) const - { - return value / toComponentBase(static_cast(ONE)); - } - } // namespace Governor } // namespace PhasorDynamics } // namespace GridKit diff --git a/GridKit/Model/PhasorDynamics/Governor/HYGOV/README.md b/GridKit/Model/PhasorDynamics/Governor/HYGOV/README.md index 31330168e..42d892fe6 100644 --- a/GridKit/Model/PhasorDynamics/Governor/HYGOV/README.md +++ b/GridKit/Model/PhasorDynamics/Governor/HYGOV/README.md @@ -20,7 +20,7 @@ Figure 1: HYGOV governor model. Figure courtesy of the Symbol | Units | JSON | Description | Typical Value | Note ------------------------|----------|---------------|------------------------------------------|---------------|------ -$T^\mathrm{rate}$ | [MW] | `Trate` | Turbine-rating power base | 100.0 | System power base when omitted +$T^\mathrm{rate}$ | [MW] | `Trate` | Turbine-rating power base | 100.0 | Required $R_{\mathrm{perm}}$ | [p.u.] | `Rperm` | Permanent droop | 0.04 | Source label: `R` $R_{\mathrm{temp}}$ | [p.u.] | `Rtemp` | Temporary droop | 0.3 | Source label: `r` $T_r$ | [sec] | `Tr` | Temporary-droop reset time constant | 5.0 | @@ -41,8 +41,8 @@ $H_{\mathrm{dam}}$ | [p.u.] | `Hdam` | Configured dam head $G_V^{(k)}$ | [p.u.] | `Gv0`-`Gv5` | Gate point $k$ of the gain curve | 0.0 | $k=0,\ldots,5$ $P_{\mathrm{GV}}^{(k)}$ | [p.u.] | `Pgv0`-`Pgv5` | Power point $k$ of the gain curve | 0.0 | $k=0,\ldots,5$ -Every parameter is optional. Real-valued parameters accept real or integer -JSON values. All-zero `Gv` and `Pgv` source points select the identity curve. +Real-valued parameters accept real or integer JSON values. All-zero `Gv` and +`Pgv` source points select the identity curve. ### Parameter Validation @@ -52,7 +52,7 @@ HYGOV parameter sets are rejected by the following checks: ```math \begin{aligned} - T^\mathrm{rate} &> 0 \quad \text{when provided} \\ + T^\mathrm{rate} &> 0 \\ T_r, T_f, T_g, T_w, T_{\mathrm{np}} &\ge 0 \\ R_{\mathrm{temp}} @@ -98,7 +98,7 @@ raised to that floor in place, so every equation below uses the raised value: &\leftarrow \max\!\left(T_x,\epsilon_T\right), \quad x\in\{r,f,g,w,\mathrm{np}\} \\ k_{\mathrm{base}} - &= \dfrac{S^\mathrm{sys}}{T^\mathrm{rate}} \\ + &= \dfrac{S^\mathrm{sys}}{10^6 T^\mathrm{rate}} \\ k_n &= \dfrac{T_n}{T_{\mathrm{np}}} \\ N_{\mathrm{GV}}(x) diff --git a/GridKit/Model/PhasorDynamics/Governor/Tgov1/Tgov1.hpp b/GridKit/Model/PhasorDynamics/Governor/Tgov1/Tgov1.hpp index 6f922a464..a212fa5bf 100644 --- a/GridKit/Model/PhasorDynamics/Governor/Tgov1/Tgov1.hpp +++ b/GridKit/Model/PhasorDynamics/Governor/Tgov1/Tgov1.hpp @@ -128,9 +128,6 @@ namespace GridKit RealT T3_{static_cast(7.5)}; RealT Dt_{ZERO}; - // Derived parameters - RealT va_component_base_{0}; - // Input States (which can be parameters) ScalarT pref_set_{0}; @@ -138,10 +135,8 @@ namespace GridKit ComponentSignals signals_; // Parameter initialization function - void initializeParameters(const ModelDataT& data); - void setDerivedParams(); - ScalarT toComponentBase(ScalarT value) const; - ScalarT toSystemBase(ScalarT value) const; + void initializeParameters(const ModelDataT& data); + void setDerivedParams(); static constexpr RealT TIME_CONSTANT_MINIMUM = static_cast(1.0e-3); static void logTimeConstantWarning(); diff --git a/GridKit/Model/PhasorDynamics/Governor/Tgov1/Tgov1Impl.hpp b/GridKit/Model/PhasorDynamics/Governor/Tgov1/Tgov1Impl.hpp index d400bed5f..812fdbe05 100644 --- a/GridKit/Model/PhasorDynamics/Governor/Tgov1/Tgov1Impl.hpp +++ b/GridKit/Model/PhasorDynamics/Governor/Tgov1/Tgov1Impl.hpp @@ -155,21 +155,7 @@ namespace GridKit T1_ = std::max(T1_, TIME_CONSTANT_MINIMUM); T3_ = std::max(T3_, TIME_CONSTANT_MINIMUM); - va_component_base_ = Trate_ * static_cast(1.0e6); - } - - // System base -> component base when reading signals. - template - scalar_type Tgov1::toComponentBase(scalar_type value) const - { - return value * va_system_base_ / va_component_base_; - } - - // Governor base -> system base for signals output. - template - scalar_type Tgov1::toSystemBase(scalar_type value) const - { - return value / toComponentBase(static_cast(ONE)); + this->setComponentBase(Trate_ * static_cast(1.0e6)); } /** @@ -300,7 +286,7 @@ namespace GridKit } const ScalarT pmech0 = y[PM]; - const ScalarT pm0 = toComponentBase(pmech0); + const ScalarT pm0 = this->toComponentBase(pmech0); const ScalarT pv0 = pm0 + Dt_ * omega0; const ScalarT pturb0 = pv0; const ScalarT pref0 = omega0 + R_ * pv0; @@ -392,7 +378,7 @@ namespace GridKit f[PTX] = -pturb_dot - (pturb - pv - T2_ * pv_dot) / T3_; f[PV] = -pv_dot + Math::antiwindup(pv, -pv + (pref - omega) / R_, Pvmin_, Pvmax_) / T1_; - f[PM] = -toComponentBase(pmech) + pturb - Dt_ * omega; + f[PM] = -this->toComponentBase(pmech) + pturb - Dt_ * omega; return 0; } diff --git a/GridKit/Model/PhasorDynamics/SynchronousMachine/GENROU/Genrou.hpp b/GridKit/Model/PhasorDynamics/SynchronousMachine/GENROU/Genrou.hpp index 1d258b5e7..8f9751e11 100644 --- a/GridKit/Model/PhasorDynamics/SynchronousMachine/GENROU/Genrou.hpp +++ b/GridKit/Model/PhasorDynamics/SynchronousMachine/GENROU/Genrou.hpp @@ -87,7 +87,6 @@ namespace GridKit using Component::J_cols_buffer_; using Component::J_vals_buffer_; using Component::freq_system_base_; - using Component::va_system_base_; using Component::variable_indices_; using Component::residual_indices_; using Component::allocated_; @@ -162,26 +161,6 @@ namespace GridKit void initializeMonitor(); void setDerivedParams(); - /** - * @brief Convert per-unit current or power from system base to machine base. - * - * @note For terminal-current quantities, this scaling assumes the machine - * voltage base matches the interfacing bus voltage base. A voltage-base - * mismatch is not a concern here because the model is formulated at the - * machine terminals using the connected bus voltage base. - */ - ScalarT toMachineBase(ScalarT value) const; - - /** - * @brief Convert per-unit current or power from machine base to system base. - * - * @note For terminal-current quantities, this scaling assumes the machine - * voltage base matches the interfacing bus voltage base. A voltage-base - * mismatch is not a concern here because the model is formulated at the - * machine terminals using the connected bus voltage base. - */ - ScalarT toSystemBase(ScalarT value) const; - ScalarT& Vr() { return bus_->Vr(); @@ -240,23 +219,21 @@ namespace GridKit RealT mva_base_{100.0}; /* Derivied parameters */ - RealT SA_; - RealT SB_; - RealT Xd1_; - RealT Xd2_; - RealT Xd3_; - RealT Xd4_; - RealT Xd5_; - RealT Xq1_; - RealT Xq2_; - RealT Xq3_; - RealT Xq4_; - RealT Xq5_; - RealT Xqd_; - RealT G_; - RealT B_; - RealT va_machine_base_; - + RealT SA_; + RealT SB_; + RealT Xd1_; + RealT Xd2_; + RealT Xd3_; + RealT Xd4_; + RealT Xd5_; + RealT Xq1_; + RealT Xq2_; + RealT Xq3_; + RealT Xq4_; + RealT Xq5_; + RealT Xqd_; + RealT G_; + RealT B_; /* Setpoints for control variables (determined at initialization) */ ScalarT pmech_set_{0.0}; // TODO remove default initialization and ensure this gets set ScalarT efd_set_{0.0}; // TODO remove default initialization and ensure this gets set diff --git a/GridKit/Model/PhasorDynamics/SynchronousMachine/GENROU/GenrouImpl.hpp b/GridKit/Model/PhasorDynamics/SynchronousMachine/GENROU/GenrouImpl.hpp index bd19514e6..8b288b909 100644 --- a/GridKit/Model/PhasorDynamics/SynchronousMachine/GENROU/GenrouImpl.hpp +++ b/GridKit/Model/PhasorDynamics/SynchronousMachine/GENROU/GenrouImpl.hpp @@ -270,33 +270,19 @@ namespace GridKit return monitor_.get(); } - // System base -> machine base when reading system values. - template - Genrou::ScalarT Genrou::toMachineBase(ScalarT value) const - { - return value * va_system_base_ / va_machine_base_; - } - - // Machine base -> system base for network and signal output. - template - Genrou::ScalarT Genrou::toSystemBase(ScalarT value) const - { - return value / toMachineBase(static_cast(ONE)); - } - template void Genrou::initializeMonitor() { using Variable = typename ModelDataT::MonitorableVariables; // Convert monitored terminal values to system base. monitor_->set(Variable::ir, [this] - { return toSystemBase(y_.getData()[15]); }); + { return this->toSystemBase(y_.getData()[15]); }); monitor_->set(Variable::ii, [this] - { return toSystemBase(y_.getData()[16]); }); + { return this->toSystemBase(y_.getData()[16]); }); monitor_->set(Variable::p, [this] - { return toSystemBase(Vr() * y_.getData()[15] + Vi() * y_.getData()[16]); }); + { return this->toSystemBase(Vr() * y_.getData()[15] + Vi() * y_.getData()[16]); }); monitor_->set(Variable::q, [this] - { return toSystemBase(Vi() * y_.getData()[15] - Vr() * y_.getData()[16]); }); + { return this->toSystemBase(Vi() * y_.getData()[15] - Vr() * y_.getData()[16]); }); monitor_->set(Variable::delta, [this] { return y_.getData()[0]; }); monitor_->set(Variable::omega, [this] @@ -400,8 +386,8 @@ namespace GridKit // Network Frame Terminal Values ScalarT vr = Vr(); ScalarT vi = Vi(); - ScalarT p = toMachineBase(static_cast(p0_)); - ScalarT q = toMachineBase(static_cast(q0_)); + ScalarT p = this->toComponentBase(static_cast(p0_)); + ScalarT q = this->toComponentBase(static_cast(q0_)); ScalarT vm2 = vr * vr + vi * vi; ScalarT ir = (p * vr + q * vi) / vm2; ScalarT ii = (p * vi - q * vr) / vm2; @@ -454,7 +440,7 @@ namespace GridKit ScalarT Te = y[12]; // Convert Te to system base for governor PM signal. - pmech_set_ = toSystemBase(Te); + pmech_set_ = this->toSystemBase(Te); if (signals_.template isAttached()) { signals_.template writeExternalVariable(pmech_set_); @@ -553,7 +539,7 @@ namespace GridKit ScalarT vi = wb[1]; // Set signal variable aliases - ScalarT pmech = toMachineBase(ws[0]); + ScalarT pmech = this->toComponentBase(ws[0]); ScalarT efd = ws[1]; static constexpr auto pi = std::numbers::pi_v; @@ -597,8 +583,8 @@ namespace GridKit ScalarT ii = y[16]; // Convert current injection to system base for the network. - h[0] = toSystemBase(ir); - h[1] = toSystemBase(ii); + h[0] = this->toSystemBase(ir); + h[1] = this->toSystemBase(ii); return 0; } @@ -669,20 +655,20 @@ namespace GridKit SA_ = SB_; SB_ = S12_ / ((SA_ - 1.2) * (SA_ - 1.2)); } - Xd1_ = Xd_ - Xdp_; - Xd2_ = Xdp_ - Xl_; - Xd3_ = (Xdp_ - Xdpp_) / (Xd2_ * Xd2_); - Xd4_ = (Xdp_ - Xdpp_) / Xd2_; - Xd5_ = (Xdpp_ - Xl_) / Xd2_; - Xq1_ = Xq_ - Xqp_; - Xq2_ = Xqp_ - Xl_; - Xq3_ = (Xqp_ - Xqpp_) / (Xq2_ * Xq2_); - Xq4_ = (Xqp_ - Xqpp_) / Xq2_; - Xq5_ = (Xqpp_ - Xl_) / Xq2_; - Xqd_ = (Xq_ - Xl_) / (Xd_ - Xl_); - G_ = Ra_ / (Ra_ * Ra_ + Xqpp_ * Xqpp_); - B_ = -Xqpp_ / (Ra_ * Ra_ + Xqpp_ * Xqpp_); - va_machine_base_ = mva_base_ * static_cast(1.0e6); + Xd1_ = Xd_ - Xdp_; + Xd2_ = Xdp_ - Xl_; + Xd3_ = (Xdp_ - Xdpp_) / (Xd2_ * Xd2_); + Xd4_ = (Xdp_ - Xdpp_) / Xd2_; + Xd5_ = (Xdpp_ - Xl_) / Xd2_; + Xq1_ = Xq_ - Xqp_; + Xq2_ = Xqp_ - Xl_; + Xq3_ = (Xqp_ - Xqpp_) / (Xq2_ * Xq2_); + Xq4_ = (Xqp_ - Xqpp_) / Xq2_; + Xq5_ = (Xqpp_ - Xl_) / Xq2_; + Xqd_ = (Xq_ - Xl_) / (Xd_ - Xl_); + G_ = Ra_ / (Ra_ * Ra_ + Xqpp_ * Xqpp_); + B_ = -Xqpp_ / (Ra_ * Ra_ + Xqpp_ * Xqpp_); + this->setComponentBase(mva_base_ * static_cast(1.0e6)); } } // namespace PhasorDynamics } // namespace GridKit diff --git a/GridKit/Model/PhasorDynamics/SynchronousMachine/GENSAL/Gensal.hpp b/GridKit/Model/PhasorDynamics/SynchronousMachine/GENSAL/Gensal.hpp index db2492c49..5b4f85cf1 100644 --- a/GridKit/Model/PhasorDynamics/SynchronousMachine/GENSAL/Gensal.hpp +++ b/GridKit/Model/PhasorDynamics/SynchronousMachine/GENSAL/Gensal.hpp @@ -80,7 +80,6 @@ namespace GridKit using Component::J_cols_buffer_; using Component::J_vals_buffer_; using Component::freq_system_base_; - using Component::va_system_base_; using Component::variable_indices_; using Component::residual_indices_; using Component::allocated_; @@ -125,26 +124,6 @@ namespace GridKit void initializeMonitor(); void setDerivedParams(); - /** - * @brief Convert per-unit current or power from system base to machine base. - * - * @note For terminal-current quantities, this scaling assumes the machine - * voltage base matches the interfacing bus voltage base. A voltage-base - * mismatch is not a concern here because the model is formulated at the - * machine terminals using the connected bus voltage base. - */ - ScalarT toMachineBase(ScalarT value) const; - - /** - * @brief Convert per-unit current or power from machine base to system base. - * - * @note For terminal-current quantities, this scaling assumes the machine - * voltage base matches the interfacing bus voltage base. A voltage-base - * mismatch is not a concern here because the model is formulated at the - * machine terminals using the connected bus voltage base. - */ - ScalarT toSystemBase(ScalarT value) const; - ScalarT& Vr() { return bus_->Vr(); @@ -199,18 +178,16 @@ namespace GridKit RealT mva_base_{100.0}; /* Derived parameters */ - RealT SA_; - RealT SB_; - RealT Xd1_; - RealT Xd2_; - RealT Xd3_; - RealT Xd4_; - RealT Xd5_; - RealT Xq2_; - RealT G_; - RealT B_; - RealT va_machine_base_; - + RealT SA_; + RealT SB_; + RealT Xd1_; + RealT Xd2_; + RealT Xd3_; + RealT Xd4_; + RealT Xd5_; + RealT Xq2_; + RealT G_; + RealT B_; /* Setpoints for control variables (determined at initialization) */ ScalarT pmech_set_{0.0}; // TODO remove default initialization and ensure this gets set ScalarT efd_set_{0.0}; // TODO remove default initialization and ensure this gets set diff --git a/GridKit/Model/PhasorDynamics/SynchronousMachine/GENSAL/GensalImpl.hpp b/GridKit/Model/PhasorDynamics/SynchronousMachine/GENSAL/GensalImpl.hpp index 96e850116..360a0b5ae 100644 --- a/GridKit/Model/PhasorDynamics/SynchronousMachine/GENSAL/GensalImpl.hpp +++ b/GridKit/Model/PhasorDynamics/SynchronousMachine/GENSAL/GensalImpl.hpp @@ -127,33 +127,19 @@ namespace GridKit return monitor_.get(); } - // System base -> machine base when reading system values. - template - scalar_type Gensal::toMachineBase(ScalarT value) const - { - return value * va_system_base_ / va_machine_base_; - } - - // Machine base -> system base for network and signal output. - template - scalar_type Gensal::toSystemBase(ScalarT value) const - { - return value / toMachineBase(static_cast(ONE)); - } - template void Gensal::initializeMonitor() { using Variable = typename ModelDataT::MonitorableVariables; // Convert monitored terminal values to system base. monitor_->set(Variable::ir, [this] - { return toSystemBase(y_.getData()[12]); }); + { return this->toSystemBase(y_.getData()[12]); }); monitor_->set(Variable::ii, [this] - { return toSystemBase(y_.getData()[13]); }); + { return this->toSystemBase(y_.getData()[13]); }); monitor_->set(Variable::p, [this] - { return toSystemBase(Vr() * y_.getData()[12] + Vi() * y_.getData()[13]); }); + { return this->toSystemBase(Vr() * y_.getData()[12] + Vi() * y_.getData()[13]); }); monitor_->set(Variable::q, [this] - { return toSystemBase(Vi() * y_.getData()[12] - Vr() * y_.getData()[13]); }); + { return this->toSystemBase(Vi() * y_.getData()[12] - Vr() * y_.getData()[13]); }); monitor_->set(Variable::delta, [this] { return y_.getData()[0]; }); monitor_->set(Variable::omega, [this] @@ -275,8 +261,8 @@ namespace GridKit // Network frame terminal values ScalarT vr = Vr(); ScalarT vi = Vi(); - ScalarT p = toMachineBase(static_cast(p0_)); - ScalarT q = toMachineBase(static_cast(q0_)); + ScalarT p = this->toComponentBase(static_cast(p0_)); + ScalarT q = this->toComponentBase(static_cast(q0_)); ScalarT vm2 = vr * vr + vi * vi; ScalarT ir = (p * vr + q * vi) / vm2; ScalarT ii = (p * vi - q * vr) / vm2; @@ -316,7 +302,7 @@ namespace GridKit y[13] = ii; // Convert Te to system base for governor PM signal. - pmech_set_ = toSystemBase(Te); + pmech_set_ = this->toSystemBase(Te); if (signals_.template isAttached()) { signals_.template writeExternalVariable(pmech_set_); @@ -411,7 +397,7 @@ namespace GridKit ScalarT vi = wb[1]; // Set signal variable aliases - ScalarT pmech = toMachineBase(ws[0]); + ScalarT pmech = this->toComponentBase(ws[0]); ScalarT efd = ws[1]; static constexpr auto pi = std::numbers::pi_v; @@ -452,8 +438,8 @@ namespace GridKit ScalarT ii = y[13]; // Convert current injection to system base for the network. - h[0] = toSystemBase(ir); - h[1] = toSystemBase(ii); + h[0] = this->toSystemBase(ir); + h[1] = this->toSystemBase(ii); return 0; } @@ -526,15 +512,15 @@ namespace GridKit } SB_ = S12_ / ((SA_ - 1.2) * (SA_ - 1.2)); } - Xd1_ = Xd_ - Xdp_; - Xd2_ = Xdp_ - Xl_; - Xd3_ = (Xdp_ - Xdpp_) / (Xd2_ * Xd2_); - Xd4_ = (Xdp_ - Xdpp_) / Xd2_; - Xd5_ = (Xdpp_ - Xl_) / Xd2_; - Xq2_ = Xq_ - Xdpp_; - G_ = Ra_ / (Ra_ * Ra_ + Xdpp_ * Xdpp_); - B_ = -Xdpp_ / (Ra_ * Ra_ + Xdpp_ * Xdpp_); - va_machine_base_ = mva_base_ * static_cast(1.0e6); + Xd1_ = Xd_ - Xdp_; + Xd2_ = Xdp_ - Xl_; + Xd3_ = (Xdp_ - Xdpp_) / (Xd2_ * Xd2_); + Xd4_ = (Xdp_ - Xdpp_) / Xd2_; + Xd5_ = (Xdpp_ - Xl_) / Xd2_; + Xq2_ = Xq_ - Xdpp_; + G_ = Ra_ / (Ra_ * Ra_ + Xdpp_ * Xdpp_); + B_ = -Xdpp_ / (Ra_ * Ra_ + Xdpp_ * Xdpp_); + this->setComponentBase(mva_base_ * static_cast(1.0e6)); } } // namespace PhasorDynamics } // namespace GridKit diff --git a/GridKit/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.hpp b/GridKit/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.hpp index ee34f2944..8733a79d7 100644 --- a/GridKit/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.hpp +++ b/GridKit/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassical.hpp @@ -72,7 +72,6 @@ namespace GridKit using Component::J_cols_buffer_; using Component::J_vals_buffer_; using Component::freq_system_base_; - using Component::va_system_base_; using Component::variable_indices_; using Component::residual_indices_; using Component::allocated_; @@ -117,26 +116,6 @@ namespace GridKit void initializeMonitor(); void setDerivedParams(); - /** - * @brief Convert per-unit current or power from system base to machine base. - * - * @note For terminal-current quantities, this scaling assumes the machine - * voltage base matches the interfacing bus voltage base. A voltage-base - * mismatch is not a concern here because the model is formulated at the - * machine terminals using the connected bus voltage base. - */ - ScalarT toMachineBase(ScalarT value) const; - - /** - * @brief Convert per-unit current or power from machine base to system base. - * - * @note For terminal-current quantities, this scaling assumes the machine - * voltage base matches the interfacing bus voltage base. A voltage-base - * mismatch is not a concern here because the model is formulated at the - * machine terminals using the connected bus voltage base. - */ - ScalarT toSystemBase(ScalarT value) const; - ScalarT& Vr() { return bus_->Vr(); @@ -184,7 +163,6 @@ namespace GridKit /* Derived parameters */ RealT G_; RealT B_; - RealT va_machine_base_; /* Setpoints for control variables (determined at initialization) */ ScalarT pmech_set_{0.0}; diff --git a/GridKit/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassicalImpl.hpp b/GridKit/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassicalImpl.hpp index 9a6e75c2e..ad76128ff 100644 --- a/GridKit/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassicalImpl.hpp +++ b/GridKit/Model/PhasorDynamics/SynchronousMachine/GenClassical/GenClassicalImpl.hpp @@ -89,33 +89,19 @@ namespace GridKit return monitor_.get(); } - // System base -> machine base when reading system values. - template - scalar_type GenClassical::toMachineBase(ScalarT value) const - { - return value * va_system_base_ / va_machine_base_; - } - - // Machine base -> system base for network and signal output. - template - scalar_type GenClassical::toSystemBase(ScalarT value) const - { - return value / toMachineBase(static_cast(ONE)); - } - template void GenClassical::initializeMonitor() { using Variable = typename ModelDataT::MonitorableVariables; // Convert monitored terminal values to system base. monitor_->set(Variable::ir, [this] - { return toSystemBase(y_.getData()[3]); }); + { return this->toSystemBase(y_.getData()[3]); }); monitor_->set(Variable::ii, [this] - { return toSystemBase(y_.getData()[4]); }); + { return this->toSystemBase(y_.getData()[4]); }); monitor_->set(Variable::p, [this] - { return toSystemBase(Vr() * y_.getData()[3] + Vi() * y_.getData()[4]); }); + { return this->toSystemBase(Vr() * y_.getData()[3] + Vi() * y_.getData()[4]); }); monitor_->set(Variable::q, [this] - { return toSystemBase(Vi() * y_.getData()[3] - Vr() * y_.getData()[4]); }); + { return this->toSystemBase(Vi() * y_.getData()[3] - Vr() * y_.getData()[4]); }); monitor_->set(Variable::delta, [this] { return y_.getData()[0]; }); monitor_->set(Variable::omega, [this] @@ -218,8 +204,8 @@ namespace GridKit // Network frame terminal values ScalarT vr = Vr(); ScalarT vi = Vi(); - ScalarT p = toMachineBase(static_cast(p0_)); - ScalarT q = toMachineBase(static_cast(q0_)); + ScalarT p = this->toComponentBase(static_cast(p0_)); + ScalarT q = this->toComponentBase(static_cast(q0_)); ScalarT vm2 = vr * vr + vi * vi; ScalarT ir = (p * vr + q * vi) / vm2; ScalarT ii = (p * vi - q * vr) / vm2; @@ -242,7 +228,7 @@ namespace GridKit y[4] = ii; // Convert Te to system base for governor PM signal. - pmech_set_ = toSystemBase(Te); + pmech_set_ = this->toSystemBase(Te); if (signals_.template isAttached()) { signals_.template writeExternalVariable(pmech_set_); @@ -325,7 +311,7 @@ namespace GridKit const ScalarT vi = wb[1]; // Set signal variable aliases - const ScalarT pmech = toMachineBase(ws[0]); + const ScalarT pmech = this->toComponentBase(ws[0]); const ScalarT efd = ws[1]; static constexpr auto pi = std::numbers::pi_v; @@ -355,8 +341,8 @@ namespace GridKit { const ScalarT ir = y[3]; const ScalarT ii = y[4]; - h[0] = toSystemBase(ir); - h[1] = toSystemBase(ii); + h[0] = this->toSystemBase(ir); + h[1] = this->toSystemBase(ii); return 0; } @@ -410,9 +396,9 @@ namespace GridKit template void GenClassical::setDerivedParams() { - G_ = Ra_ / (Ra_ * Ra_ + Xdp_ * Xdp_); - B_ = -Xdp_ / (Ra_ * Ra_ + Xdp_ * Xdp_); - va_machine_base_ = mva_base_ * static_cast(1.0e6); + G_ = Ra_ / (Ra_ * Ra_ + Xdp_ * Xdp_); + B_ = -Xdp_ / (Ra_ * Ra_ + Xdp_ * Xdp_); + this->setComponentBase(mva_base_ * static_cast(1.0e6)); } } // namespace PhasorDynamics diff --git a/tests/UnitTests/PhasorDynamics/ComponentConnectionTests.hpp b/tests/UnitTests/PhasorDynamics/ComponentConnectionTests.hpp index 5f3c2e94b..bd2bf2928 100644 --- a/tests/UnitTests/PhasorDynamics/ComponentConnectionTests.hpp +++ b/tests/UnitTests/PhasorDynamics/ComponentConnectionTests.hpp @@ -114,7 +114,8 @@ namespace GridKit PhasorDynamics::Genrou machine(&bus); PhasorDynamics::Governor::HygovData governor_data; - governor_data.parameters[GovernorParams::Tnp] = static_cast(1.0); + governor_data.parameters[GovernorParams::Trate] = static_cast(100.0); + governor_data.parameters[GovernorParams::Tnp] = static_cast(1.0); PhasorDynamics::Governor::Hygov governor(governor_data); @@ -213,7 +214,8 @@ namespace GridKit PhasorDynamics::GenClassical machine(&bus, machine_data); PhasorDynamics::Governor::HygovData governor_data; - governor_data.parameters[GovernorParams::Tnp] = static_cast(1.0); + governor_data.parameters[GovernorParams::Trate] = static_cast(100.0); + governor_data.parameters[GovernorParams::Tnp] = static_cast(1.0); PhasorDynamics::Governor::Hygov governor(governor_data); diff --git a/tests/UnitTests/PhasorDynamics/ControllerReecbTests.hpp b/tests/UnitTests/PhasorDynamics/ControllerReecbTests.hpp index a4c5d34e9..601eee018 100644 --- a/tests/UnitTests/PhasorDynamics/ControllerReecbTests.hpp +++ b/tests/UnitTests/PhasorDynamics/ControllerReecbTests.hpp @@ -114,6 +114,11 @@ namespace GridKit success *= (documented_defaults.reecb.verify() == 0); success *= defaultsMatchDocumentedValues(); + auto missing_mva_data = makeMinimalData(); + missing_mva_data.parameters.erase(Params::mva); + Fixture missing_mva(missing_mva_data); + success *= (missing_mva.reecb.verify() > 0); + // Integer JSON values are accepted for real parameters; booleans are // not numeric. auto integer_numeric = makeData(); @@ -365,25 +370,6 @@ namespace GridKit success *= isEqual(tracked_state[iqcmd_index].getDependencies(), iqcmd_dependencies); success *= isEqual(tracked_state[ipcmd_index].getDependencies(), ipcmd_dependencies); - // An omitted component rating falls back to the system power base, so - // the same commands land on a different measured power. - auto system_base_data = makeData(); - system_base_data.parameters.erase(Params::mva); - Fixture system_base(system_base_data, 1.0, 0.0, static_cast(50.0e6)); - system_base.attachAllInputs(); - system_base.input(Ext::PE) = 0.75; - success *= system_base.initialize(kInitialIqcmd, 1.5); - success *= (system_base.evaluate() == 0); - success *= stateMatches(system_base.reecb, - {{Vars::PMEAS, 0.75}, - {Vars::PORD, 1.5}}, - "omitted component rating"); - success *= stateMatches(system_base.reecb, - {{Vars::ILCAP, 2.0}}, - "omitted-rating current-circle capacity", - kCircleTol); - success *= allResidualsWithinInitTolerance(system_base.reecb); - return success.report(__func__); } @@ -1985,8 +1971,9 @@ namespace GridKit Data makeMinimalData() const { Data data; - data.device_class = "Reecb"; - data.disambiguation_string = "reecb_test"; + data.device_class = "Reecb"; + data.disambiguation_string = "reecb_test"; + data.parameters[Params::mva] = 100.0; data.monitored_variables.insert(Mon::iqcmd); data.monitored_variables.insert(Mon::ipcmd); data.monitored_variables.insert(Mon::vmeas); @@ -2249,8 +2236,8 @@ namespace GridKit fixture.reecb.yp().setDataUpdated(); } - /// Omitting every parameter must give exactly the model built from the - /// defaults the README documents, at rest and under load. + /// Omitting every optional parameter must give exactly the model built + /// from the defaults the README documents, at rest and under load. bool defaultsMatchDocumentedValues() const { Fixture implicit_defaults(makeMinimalData(), kStateVr, kStateVi); diff --git a/tests/UnitTests/PhasorDynamics/GovernorGastPtiTests.hpp b/tests/UnitTests/PhasorDynamics/GovernorGastPtiTests.hpp index 960bdf41b..7cd1e3253 100644 --- a/tests/UnitTests/PhasorDynamics/GovernorGastPtiTests.hpp +++ b/tests/UnitTests/PhasorDynamics/GovernorGastPtiTests.hpp @@ -84,7 +84,10 @@ namespace GridKit success *= (minimal.verify() > 0); // required pmech assignment is absent success *= (verifyData(makeData()) == 0); success *= defaultsMatchDocumentedValues(); - success *= omittedRatingUsesSystemBase(); + + auto missing_trate = makeMinimalData(); + missing_trate.parameters.erase(Params::Trate); + success *= (verifyData(missing_trate) > 0); success *= invalidParameterCase(Params::R, 0.0); success *= invalidParameterCase(Params::R, -0.1); @@ -1059,8 +1062,9 @@ namespace GridKit Data makeMinimalData() const { Data data; - data.device_class = "GastPti"; - data.disambiguation_string = "gastpti_test"; + data.device_class = "GastPti"; + data.disambiguation_string = "gastpti_test"; + data.parameters[Params::Trate] = 100.0; data.monitored_variables.insert(Mon::pmech); data.monitored_variables.insert(Mon::xvalve); data.monitored_variables.insert(Mon::xflow); @@ -1153,8 +1157,8 @@ namespace GridKit {Internal::XTEMP, 0.03}}); } - /// Omitting every parameter must give exactly the model built from the - /// defaults the README documents, at rest and under load. + /// Omitting every optional parameter must give exactly the model built + /// from the defaults the README documents, at rest and under load. bool defaultsMatchDocumentedValues() const { Fixture implicit_defaults(makeMinimalData()); @@ -1218,56 +1222,6 @@ namespace GridKit return success; } - /// An omitted rating follows a system-base change made after allocation. - bool omittedRatingUsesSystemBase() const - { - constexpr RealT system_va_base = static_cast(75.0e6); - - auto omitted_data = makeExplicitDefaultData(); - omitted_data.parameters.erase(Params::Trate); - auto explicit_data = omitted_data; - explicit_data.parameters[Params::Trate] = static_cast(75.0); - - Fixture omitted(omitted_data); - Fixture explicit_system_base(explicit_data, system_va_base); - omitted.attachAllInputs(); - explicit_system_base.attachAllInputs(); - - bool success = omitted.prepare(0.3); - omitted.gastpti.setSystemBase(60.0, system_va_base); - success = success && omitted.gastpti.initialize() == 0 - && explicit_system_base.initialize(0.3); - if (!success) - { - std::cout << "GASTPTI omitted-rating comparison failed to initialize\n"; - return false; - } - - if (omitted.evaluate() != 0 || explicit_system_base.evaluate() != 0) - { - success = false; - } - if (!vectorUnchanged(omitted.gastpti.y(), - copyVector(explicit_system_base.gastpti.y()), - "omitted-rating state")) - { - success = false; - } - if (!vectorUnchanged(omitted.gastpti.getResidual(), - copyVector(explicit_system_base.gastpti.getResidual()), - "omitted-rating residual")) - { - success = false; - } - if (!scalarMatches(omitted.input(index(External::PREF)), - explicit_system_base.input(index(External::PREF)), - "omitted-rating published pref")) - { - success = false; - } - return success; - } - template bool invalidParameterCase(Params parameter, ValueT value) const { diff --git a/tests/UnitTests/PhasorDynamics/GovernorHygovTests.hpp b/tests/UnitTests/PhasorDynamics/GovernorHygovTests.hpp index 175799562..8f673163e 100644 --- a/tests/UnitTests/PhasorDynamics/GovernorHygovTests.hpp +++ b/tests/UnitTests/PhasorDynamics/GovernorHygovTests.hpp @@ -68,6 +68,11 @@ namespace GridKit success *= (minimal.hygov.verify() == 0); success *= defaultsMatchDocumentedValues(); + auto missing_trate_data = makeMinimalData(); + missing_trate_data.parameters.erase(Params::Trate); + Fixture missing_trate(missing_trate_data); + success *= (missing_trate.hygov.verify() > 0); + success *= (empty.verify() > 0); const RealT nan = std::numeric_limits::quiet_NaN(); @@ -1054,8 +1059,9 @@ namespace GridKit Data makeMinimalData() const { Data data; - data.device_class = "Hygov"; - data.disambiguation_string = "hygov_test"; + data.device_class = "Hygov"; + data.disambiguation_string = "hygov_test"; + data.parameters[Params::Trate] = 100.0; data.monitored_variables.insert(Mon::pmech); data.monitored_variables.insert(Mon::filter); data.monitored_variables.insert(Mon::desiredgate); diff --git a/tests/UnitTests/PhasorDynamics/SystemSingleComponentTests.hpp b/tests/UnitTests/PhasorDynamics/SystemSingleComponentTests.hpp index e25463361..570949e09 100644 --- a/tests/UnitTests/PhasorDynamics/SystemSingleComponentTests.hpp +++ b/tests/UnitTests/PhasorDynamics/SystemSingleComponentTests.hpp @@ -314,6 +314,7 @@ namespace GridKit TestOutcome gastpti() { using Outputs = PhasorDynamics::Governor::GastPtiSignalOutputs; + using Params = PhasorDynamics::Governor::GastPtiParameters; using Vars = PhasorDynamics::Governor::GastPtiInternalVariables; TestStatus success = true; @@ -326,6 +327,7 @@ namespace GridKit auto& gastpti = data.gastpti.emplace_back(); gastpti.device_class = "GastPti"; gastpti.disambiguation_string = "gastpti_test"; + gastpti.parameters[Params::Trate] = static_cast(100.0); gastpti.signal_outputs[Outputs::pmech] = static_cast(1); PhasorDynamics::SystemModel system(data); @@ -361,6 +363,7 @@ namespace GridKit Data reecb_data; reecb_data.buses[Buses::bus] = bus_id; + reecb_data.parameters[Params::mva] = static_cast(100.0); reecb_data.parameters[Params::Tp] = static_cast(0.02); reecb_data.parameters[Params::Pmin] = static_cast(-1.0); data.reecb.push_back(reecb_data);