Skip to main content

surge_network/network/
dc_line.rs

1// SPDX-License-Identifier: LicenseRef-PolyForm-Noncommercial-1.0.0
2//! Two-terminal LCC-HVDC line data structures.
3//!
4//! A two-terminal DC line connects a rectifier bus (AC → DC) and an
5//! inverter bus (DC → AC) through a DC circuit with resistance `resistance_ohm`.
6//! PSS/E RAW section: "TWO-TERMINAL DC DATA".
7
8use serde::{Deserialize, Serialize};
9
10/// Control mode for a two-terminal LCC-HVDC link.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
12pub enum LccHvdcControlMode {
13    /// Line is blocked (out of service).
14    Blocked = 0,
15    /// Power control: SETVL is scheduled MW.
16    #[default]
17    PowerControl = 1,
18    /// Current control: SETVL is scheduled kA.
19    CurrentControl = 2,
20}
21
22impl LccHvdcControlMode {
23    /// Convert a PSS/E MDC integer to a `LccHvdcControlMode`. Out-of-range values map to `Blocked`.
24    pub fn from_u32(v: u32) -> Self {
25        match v {
26            1 => Self::PowerControl,
27            2 => Self::CurrentControl,
28            _ => Self::Blocked,
29        }
30    }
31}
32
33/// One converter terminal (rectifier or inverter) of a two-terminal LCC-HVDC link.
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct LccConverterTerminal {
36    /// AC bus number this converter is connected to.
37    pub bus: u32,
38    /// Number of 6-pulse converter bridges (NBR / NBI).
39    #[serde(alias = "num_bridges")]
40    pub n_bridges: u32,
41    /// Maximum firing/extinction angle in degrees (ALFMX / GAMMX).
42    pub alpha_max: f64,
43    /// Minimum firing/extinction angle in degrees (ALFMN / GAMMN).
44    pub alpha_min: f64,
45    /// Commutating resistance per bridge in ohms (RCR / RCI).
46    pub commutation_resistance_ohm: f64,
47    /// Commutating reactance per bridge in ohms (XCR / XCI).
48    pub commutation_reactance_ohm: f64,
49    /// Converter transformer rated AC voltage (line-to-line kV) on the network side (EBASR / EBASI).
50    pub base_voltage_kv: f64,
51    /// Transformer turns ratio (EBASR/EBASI side to converter side) (TRR / TRI).
52    pub turns_ratio: f64,
53    /// Off-nominal tap ratio (TAPR / TAPI), default 1.0.
54    pub tap: f64,
55    /// Maximum tap ratio (TMXR / TMXI).
56    pub tap_max: f64,
57    /// Minimum tap ratio (TMNR / TMNI).
58    pub tap_min: f64,
59    /// Tap step size (STPR / STPI), 0 = continuous.
60    pub tap_step: f64,
61    /// Converter in-service flag (ICR / ICI == 1).
62    pub in_service: bool,
63}
64
65impl Default for LccConverterTerminal {
66    fn default() -> Self {
67        Self {
68            bus: 0,
69            n_bridges: 1,
70            alpha_max: 90.0,
71            alpha_min: 5.0,
72            commutation_resistance_ohm: 0.0,
73            commutation_reactance_ohm: 0.0,
74            base_voltage_kv: 0.0,
75            turns_ratio: 1.0,
76            tap: 1.0,
77            tap_max: 1.1,
78            tap_min: 0.9,
79            tap_step: 0.00625,
80            in_service: true,
81        }
82    }
83}
84
85/// Two-terminal LCC-HVDC link (PSS/E TWO-TERMINAL DC DATA section).
86///
87/// Models a point-to-point high-voltage DC link with line-commutated
88/// converters (thyristor bridges). The rectifier converts AC power to DC;
89/// the inverter converts DC power back to AC.
90///
91/// For power flow with `FixedSchedule` DC model the converter power is
92/// computed from `setvl`/`vschd` and injected as constant PQ at the
93/// converter buses. With `SequentialAcDc`, the AC/DC operating point is
94/// iterated to convergence.
95///
96/// When `p_dc_min_mw < p_dc_max_mw` the link exposes an optimization
97/// variable rather than a fixed setpoint — used by the joint AC-DC OPF
98/// path (`build_hvdc_p2p_nlp_data`) to put HVDC P into the NLP.
99#[derive(Debug, Clone, Serialize, Deserialize)]
100pub struct LccHvdcLink {
101    /// Name / identifier of the DC link.
102    pub name: String,
103    /// Control mode (0 = blocked, 1 = power control, 2 = current control).
104    pub mode: LccHvdcControlMode,
105    /// DC circuit resistance in ohms.
106    pub resistance_ohm: f64,
107    /// Scheduled DC power (MW) for MDC=1, or scheduled current (kA) for MDC=2.
108    pub scheduled_setpoint: f64,
109    /// Scheduled DC voltage in kV.
110    pub scheduled_voltage_kv: f64,
111    /// Max DC voltage for mode switching in kV (VCMOD).
112    pub voltage_mode_switch_kv: f64,
113    /// Compounding resistance in ohms (RCOMP).
114    pub compounding_resistance_ohm: f64,
115    /// Current margin in kA (DELTI).
116    pub current_margin_ka: f64,
117    /// Metering end: `'R'` = rectifier-metered, `'I'` = inverter-metered.
118    pub meter: char,
119    /// Minimum DC voltage in kV (DCVMIN).
120    pub voltage_min_kv: f64,
121    /// Maximum AC/DC outer-loop iterations (CCCITMX).
122    pub ac_dc_iteration_max: u32,
123    /// Acceleration factor for AC/DC iteration (CCCACC).
124    pub ac_dc_iteration_acceleration: f64,
125    /// Rectifier terminal (AC bus → DC).
126    pub rectifier: LccConverterTerminal,
127    /// Inverter terminal (DC → AC bus).
128    pub inverter: LccConverterTerminal,
129    /// Minimum DC power setpoint in MW for joint AC-DC OPF.
130    ///
131    /// When `p_dc_min_mw < p_dc_max_mw`, the joint AC-DC OPF will treat
132    /// this link's DC power as a decision variable bounded in
133    /// `[p_dc_min_mw, p_dc_max_mw]` rather than using the fixed
134    /// `scheduled_setpoint`. Default `0.0` (no variable range → fall back
135    /// to the sequential-iteration path with a fixed setpoint).
136    #[serde(default)]
137    pub p_dc_min_mw: f64,
138    /// Maximum DC power setpoint in MW for joint AC-DC OPF.
139    ///
140    /// When `p_dc_min_mw < p_dc_max_mw`, the joint AC-DC OPF will treat
141    /// this link's DC power as a decision variable bounded in
142    /// `[p_dc_min_mw, p_dc_max_mw]`. Default `0.0`.
143    #[serde(default)]
144    pub p_dc_max_mw: f64,
145}
146
147impl Default for LccHvdcLink {
148    fn default() -> Self {
149        Self {
150            name: String::new(),
151            mode: LccHvdcControlMode::PowerControl,
152            resistance_ohm: 0.0,
153            scheduled_setpoint: 0.0,
154            scheduled_voltage_kv: 500.0,
155            voltage_mode_switch_kv: 0.0,
156            compounding_resistance_ohm: 0.0,
157            current_margin_ka: 0.0,
158            meter: 'I',
159            voltage_min_kv: 0.0,
160            ac_dc_iteration_max: 20,
161            ac_dc_iteration_acceleration: 1.0,
162            rectifier: LccConverterTerminal::default(),
163            inverter: LccConverterTerminal::default(),
164            p_dc_min_mw: 0.0,
165            p_dc_max_mw: 0.0,
166        }
167    }
168}
169
170impl LccHvdcLink {
171    /// Returns `true` when the joint AC-DC OPF should treat this link's
172    /// DC power as an NLP decision variable (i.e. `[p_dc_min_mw,
173    /// p_dc_max_mw]` is a non-degenerate interval).
174    pub fn has_variable_p_dc(&self) -> bool {
175        self.p_dc_min_mw < self.p_dc_max_mw
176    }
177}