Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
use flake
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ namespace GridKit
* - publishes _Vr_ and _Vi_ on signal outlets `vr` and `vi`, and
* - sets its residuals f[0] and f[1] to the current injections read from
* signal inlets `ir` and `ii`, respectively. Both inlets are
* mandatory: verify() reports an error if either is not connected to a linked
* signal, and no default value is ever used.
* mandatory: verify() reports an error if either is not connected to a
* linked signal, and no default value is ever used.
*
* Components attached to the bus directly (without signals) keep adding
* their currents to the residuals after the bus residual is evaluated,
* exactly as they do for @ref Bus.
*
* @note Signal ports have to be connected before allocate() is called, since
* the output signals are linked to the bus variables there.
* @note Signal ports have to be connected before allocate() is called,
* since the output signals are linked to the bus variables there.
*/
template <typename scalar_type, typename index_type>
class BusSignalVoltageOut : public BusBase<scalar_type, index_type>
Expand Down Expand Up @@ -67,6 +67,7 @@ namespace GridKit
virtual ~BusSignalVoltageOut();

virtual int setBusID(IdxT) override final;
virtual int setFault(bool status, RealT R, RealT X) override final;
virtual int allocate() override final;
Comment on lines +70 to 71

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest we make busses with associated signals "unfaultable". When you dedicate a bus as a co-simulation connection point, you typically don't want to fault it.

Suggested change
virtual int setFault(bool status, RealT R, RealT X) override final;
virtual int allocate() override final;
virtual int allocate() override final;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, remove fault support for signal connected buses elsewhere in the code.

virtual int tagDifferentiable() override final;
virtual int setAbsoluteTolerance(RealT rel_tol) override final;
Expand Down Expand Up @@ -192,6 +193,8 @@ namespace GridKit
private:
ScalarT Vr0_{0.0};
ScalarT Vi0_{0.0};
RealT fault_g_{0.0};
RealT fault_b_{0.0};

/// Signal ports
SignalPortsT ports_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@ namespace GridKit
/**
* @brief Jacobian evaluation for the Enzyme build.
*
* The first four entries are zero placeholders for the bus voltage
* columns, as in Bus. They provide the indices for entries that other
* components contribute to and that are later deduplicated.
* This sets the fault admittance terms of the bus which are zero when
* cleared.
*
* One additional entry per connected signal inlet holds the derivative of
* the residual with respect to the signal variable, which is one. When
Expand Down Expand Up @@ -58,10 +57,10 @@ namespace GridKit
J_cols_buffer_[1] = variable_indices_.at(1);
J_cols_buffer_[2] = variable_indices_.at(0);
J_cols_buffer_[3] = variable_indices_.at(1);
J_vals_buffer_[0] = 0.0;
J_vals_buffer_[1] = 0.0;
J_vals_buffer_[2] = 0.0;
J_vals_buffer_[3] = 0.0;
J_vals_buffer_[0] = -fault_g_;
J_vals_buffer_[1] = fault_b_;
J_vals_buffer_[2] = -fault_b_;
J_vals_buffer_[3] = -fault_g_;

IdxT k = num_bus_entries;

Expand All @@ -71,8 +70,9 @@ namespace GridKit
{
return;
}
const IdxT signal_index = port.linked() ? port.signalVariableIndex() : INVALID_INDEX<IdxT>;
J_rows_buffer_[k] = residual_indices_.at(residual);
const IdxT signal_index =
port.linked() ? port.signalVariableIndex() : INVALID_INDEX<IdxT>;
J_rows_buffer_[k] = residual_indices_.at(residual);
if (signal_index != INVALID_INDEX<IdxT>)
{
J_cols_buffer_[k] = signal_index;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ namespace GridKit
*/
template <typename scalar_type, typename index_type>
BusSignalVoltageOut<scalar_type, index_type>::BusSignalVoltageOut(const ModelDataT& data)
: Vr0_(data.Vr0),
Vi0_(data.Vi0)
: Vr0_(data.Vr0), Vi0_(data.Vi0)
{
bus_id_ = data.bus_id;
size_ = 2;
Expand All @@ -57,8 +56,9 @@ namespace GridKit
{ return Vr(); });
monitor_->set(Variable::Vi, [this]
{ return Vi(); });
monitor_->set(Variable::Vm, [this]
{ return std::sqrt(Vr() * Vr() + Vi() * Vi()); });
monitor_->set(
Variable::Vm, [this]
{ return std::sqrt(Vr() * Vr() + Vi() * Vi()); });
monitor_->set(Variable::Va, [this]
{ return std::atan2(Vi(), Vr()); });
}
Expand Down Expand Up @@ -144,11 +144,15 @@ namespace GridKit
const auto& port = ports_.in.template port<input>();
if (!port.connected())
{
checks.fail(std::format("{} signal inlet is not connected; a default current is not allowed", name));
checks.fail(std::format(
"{} signal inlet is not connected; a default current is not "
"allowed",
name));
}
else if (!port.linked())
{
checks.fail(std::format("{} signal attached with no linked source", name));
checks.fail(
std::format("{} signal attached with no linked source", name));
}
};

Expand All @@ -157,7 +161,10 @@ namespace GridKit
const auto& port = ports_.out.template port<output>();
if (port.connected() && !port.linked())
{
checks.fail(std::format("{} signal attached but not linked; connect signal ports before allocate()", name));
checks.fail(std::format(
"{} signal attached but not linked; connect signal ports before "
"allocate()",
name));
}
};

Expand All @@ -179,6 +186,28 @@ namespace GridKit
return 0;
}

template <typename scalar_type, typename index_type>
int BusSignalVoltageOut<scalar_type, index_type>::setFault(bool status, RealT R, RealT X)
{
if (status && !(ZERO<RealT> < R * R + X * X))
{
Log::error()
<< "BusSignalVoltageOut: fault impedance R + jX must be nonzero\n";
return 1;
}

fault_g_ = ZERO<RealT>;
fault_b_ = ZERO<RealT>;

if (status)
{
fault_g_ = R / (R * R + X * X);
fault_b_ = -X / (R * R + X * X);
}

return 0;
}

/*!
* @brief Bus variables are algebraic.
*/
Expand Down Expand Up @@ -235,9 +264,9 @@ namespace GridKit
*
* Residuals f[0] and f[1] are set to the values read from the `ir` and
* `ii` signal inlets, respectively. Both inlets are mandatory; verify()
* reports an error if either is not connected to a linked signal, and no default
* value is used here. Components attached to the bus add their currents
* afterwards.
* reports an error if either is not connected to a linked signal, and no
* default value is used here. Components attached to the bus add their
* currents afterwards.
*
* @warning This implementation assumes bus residuals are always evaluated
* _before_ component model residuals.
Expand All @@ -247,8 +276,10 @@ namespace GridKit
{
auto* f = f_.getData();

f[0] = ports_.in.template port<BusSignalInputs::ir>().readSignal();
f[1] = ports_.in.template port<BusSignalInputs::ii>().readSignal();
f[0] = ports_.in.template port<BusSignalInputs::ir>().readSignal()
- (fault_g_ * Vr() - fault_b_ * Vi());
f[1] = ports_.in.template port<BusSignalInputs::ii>().readSignal()
- (fault_b_ * Vr() + fault_g_ * Vi());

f_.setDataUpdated();
return 0;
Expand Down
49 changes: 26 additions & 23 deletions GridKit/Model/PhasorDynamics/Bus/BusSignalVoltageOut/README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# BusSignalVoltageOut

`BusSignalVoltageOut` is a bus with signal ports. It owns the same voltage variables
and current-balance residuals as `Bus`, publishes the voltage components on
output signals, and adds current injections received on input signals to its
residuals. Devices attached directly to the bus still add their currents after
the bus residual is evaluated.
`BusSignalVoltageOut` is a bus with signal ports. It owns the same voltage
variables and current-balance residuals as `Bus`, publishes the voltage
components on output signals, and adds current injections received on input
signals to its residuals. Devices attached directly to the bus still add their
currents after the bus residual is evaluated.

## Notes

- Signal ports must be connected before `allocate()` is called. The signal outlets
are linked to the bus voltage variables and their system indices in
`allocate()`.
- Signal ports must be connected before `allocate()` is called. The signal
outlets are linked to the bus voltage variables and their system indices
in `allocate()`.
- Both current inlets are mandatory. `verify()` reports an error if a
current inlet is not connected or not linked, or if a
connected outlet is not linked. No default current is ever used.
Expand All @@ -22,12 +22,14 @@ Same as `Bus`.

## Model Ports

Signal | Direction | Units | Description | Note
-----|-----------|--------|----------------------------------------------------|-----
`vr` | out | [p.u.] | Bus voltage, real component $V_r$ |
`vi` | out | [p.u.] | Bus voltage, imaginary component $V_i$ |
`ir` | in | [p.u.] | Current injection, real component $I_r^{s}$ | Required, sets $f_0$
`ii` | in | [p.u.] | Current injection, imaginary component $I_i^{s}$ | Required, sets $f_1$
Signal | Direction | Units | Description
-------|-----------|-------|-----------------------------------------
`vr` | out | [p.u.] | Bus voltage, real component $V_r$
`vi` | out | [p.u.] | Bus voltage, imaginary component $V_i$
`ir` | in | [p.u.] | Current injection, real component $I_r^{s}$
`ii` | in | [p.u.] | Current injection, imaginary component $I_i^{s}$

Both current inputs are required. `ir` sets $f_0$, and `ii` sets $f_1$.

## Model Variables

Expand Down Expand Up @@ -55,17 +57,18 @@ $I_i^{s}$ | [p.u.] | Current injection on signal inlet `ii` |

#### Algebraic

Let $\mathcal{D}$ denote the set of devices attached directly to the bus.
Let $\mathcal{D}$ denote the set of devices attached directly to the bus
and $G_f$, $B_f$ be the conductance and susceptance of a fault applied
to the bus, respectively. During a fault, $G_f + jB_f = 1/(R_f + jX_f)$.
Otherwise, both are zero.

```math
\begin{aligned}
0 &= I_r^{s} + \sum_{d \in \mathcal{D}} I_{r,d} \\
0 &= I_i^{s} + \sum_{d \in \mathcal{D}} I_{i,d}
0 &= I_r^{s} - (G_f V_r - B_f V_i) + \sum_{d \in \mathcal{D}} I_{r,d} \\
0 &= I_i^{s} - (B_f V_r + G_f V_i) + \sum_{d \in \mathcal{D}} I_{i,d}
\end{aligned}
```

Both signal inlets must be connected; see `verify()`.

## Initialization

Same as `Bus`.
Expand All @@ -76,7 +79,7 @@ Same as `Bus`.

## Testing

Unit tests in `tests/UnitTests/PhasorDynamics/BusSignalVoltageOutTests.hpp` cover
construction, output signal linking, residual evaluation with input signals,
verification of unlinked inputs, dependency-tracking derivatives, and (when
Enzyme is enabled) the sparse Jacobian entries.
Unit tests in `tests/UnitTests/PhasorDynamics/BusSignalVoltageOutTests.hpp`
cover construction, output signal linking, residual evaluation with input
signals, verification of unlinked inputs, dependency-tracking derivatives,
and (when Enzyme is enabled) the sparse Jacobian entries.
2 changes: 2 additions & 0 deletions GridKit/Solver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
# - Slaven Peles <slaven.peles@pnnl.gov>
#]]

install(FILES SundialsException.hpp DESTINATION include/GridKit/Solver)

if(TARGET SUNDIALS::kinsol)
add_subdirectory(SteadyState)
endif()
Expand Down
Loading
Loading