Skip to main content

gridoxide_core/linear/
mod.rs

1//! Linearized power-flow methods: the two different things the literature and
2//! the reference tools both call "linear power flow".
3//!
4//! - [`btheta`] is the **DC approximation**: real-valued, `B θ = P`, voltage
5//!   magnitudes asserted to 1 p.u. and resistance discarded. It answers
6//!   "how does active power divide between these paths", exactly, in one
7//!   factorization and no iterations. This is what lightsim2grid,
8//!   powsybl-open-loadflow and pandapower's `rundcpp` mean by DC power flow.
9//! - [`impedance`] is the **constant-admittance linearization**: complex,
10//!   `Y' U = I`, every load replaced by the admittance that would draw its
11//!   rated power at `|V| = 1`. It keeps resistance and produces voltage
12//!   *magnitudes*, which Bθ cannot. This is what power-grid-model means by
13//!   `CalculationMethod.linear`.
14//!
15//! Neither approximates the other. Bθ is the transmission tool: on a meshed
16//! network with small angle differences and `r << x` its flows are close to
17//! the AC answer, and its exactness under linearity is what makes the
18//! sensitivity factors in [`sensitivity`] meaningful. The constant-admittance
19//! form is the distribution tool: it tracks the voltage drop along a feeder,
20//! which is the quantity that actually matters there and the one Bθ throws
21//! away by construction.
22//!
23//! **Not to be confused with [`crate::dc`]**, which despite the name is not an
24//! approximation at all — it is the genuine HVDC network solver
25//! (`DcBus`/`DcLine`/`solve_dc_network`) that `crate::cgmes` uses to resolve
26//! converter stations. That module models real DC hardware; this one
27//! approximates AC.
28
29pub mod batch;
30pub mod btheta;
31pub mod impedance;
32pub mod sensitivity;
33
34pub use batch::{DcBatchResult, DcBatchSolver};
35pub use btheta::{
36    DcBranch, DcIslandReport, DcIslandStatus, DcSolution, dc_branches, dc_power_flow,
37};
38pub use impedance::{LinearIslandReport, LinearIslandStatus, LinearReport, linear_power_flow};
39pub use sensitivity::{DcSensitivity, DenseMatrix};
40
41/// Which terms the DC susceptance keeps.
42///
43/// Both variants are powsybl-open-loadflow's `DcApproximationType`
44/// (`dc/equations/AbstractClosedBranchDcFlowEquationTerm.computePower`); no
45/// other reference tool offers the choice, and every one of them uses what is
46/// spelled [`IgnoreR`](Self::IgnoreR) here.
47#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
48pub enum DcApproximation {
49    /// `b = 1/x`. The textbook DC approximation, and what MATPOWER's
50    /// `makeBdc`, pandapower's `rundcpp` and lightsim2grid all compute.
51    /// Discards resistance entirely, which is the assumption the whole DC
52    /// model rests on anyway.
53    #[default]
54    IgnoreR,
55    /// `b = x/(r² + x²)`, i.e. `−Im(y_series)`: the true series susceptance,
56    /// with resistance retained in the denominator where it belongs.
57    ///
58    /// Strictly the better linearization of the two — it is the exact
59    /// coefficient of `sin δ` in the AC flow equation, whereas `1/x` is that
60    /// coefficient only in the limit `r → 0`. The gap is negligible on
61    /// transmission (`r/x ≈ 0.1` gives a 1% difference) and material on
62    /// distribution feeders, where `r/x` can exceed 1. It is not the default
63    /// only because every tool worth comparing against uses `1/x`, and a
64    /// default that silently disagrees with all of them would make every
65    /// cross-check look like a bug.
66    IgnoreG,
67}
68
69/// Configuration for the DC (Bθ) solver and for [`sensitivity::DcSensitivity`].
70///
71/// Deliberately small: DC has no tolerance and no iteration limit, because it
72/// is a direct solve. The only real choices are which susceptance to use and
73/// whether transformer ratios participate.
74#[derive(Clone, Copy, Debug, PartialEq)]
75pub struct DcOptions {
76    pub approximation: DcApproximation,
77    /// Whether an off-nominal transformer ratio `k = |tap|` divides the
78    /// branch susceptance (`b/k`). True by default, matching MATPOWER
79    /// (`b ./ tap`) and powsybl (`useTransformerRatio`). Setting it false
80    /// reproduces the cruder "ratios are all 1" approximation some
81    /// contingency tools still assume.
82    pub use_transformer_ratio: bool,
83}
84
85impl Default for DcOptions {
86    fn default() -> Self {
87        Self {
88            approximation: DcApproximation::default(),
89            use_transformer_ratio: true,
90        }
91    }
92}