surge_network/network/protection.rs
1// SPDX-License-Identifier: LicenseRef-PolyForm-Noncommercial-1.0.0
2//! Protection equipment data types (IEC 61970-302 Protection package).
3//!
4//! Stores relay settings, auto-reclose sequences, and synchrocheck parameters
5//! parsed from CGMES protection profile data. These are informational/metadata
6//! types — they do not affect power flow computation but are preserved for
7//! downstream protection coordination tools (e.g., surge-fault TCC analysis).
8
9use serde::{Deserialize, Serialize};
10
11/// Overcurrent relay settings (IEC 61970-302 CurrentRelay).
12#[derive(Debug, Clone, Default, Serialize, Deserialize)]
13pub struct CurrentRelaySettings {
14 /// CIM mRID.
15 pub mrid: String,
16 /// Relay name.
17 pub name: String,
18 /// Phase pickup current (A).
19 pub phase_pickup_a: Option<f64>,
20 /// Ground pickup current (A).
21 pub ground_pickup_a: Option<f64>,
22 /// Negative-sequence pickup (A).
23 pub neg_seq_pickup_a: Option<f64>,
24 /// Phase time dial (s).
25 pub phase_time_dial_s: Option<f64>,
26 /// Ground time dial (s).
27 pub ground_time_dial_s: Option<f64>,
28 /// Neg-seq time dial (s).
29 pub neg_seq_time_dial_s: Option<f64>,
30 /// True = inverse-time characteristic, false = definite-time.
31 pub inverse_time: bool,
32 /// Directional element.
33 pub directional: bool,
34 /// Bus where CTs are located.
35 pub bus: Option<u32>,
36 /// Protected switch/breaker mRID.
37 pub protected_switch_mrid: Option<String>,
38}
39
40/// Distance relay settings (IEC 61970-302 DistanceRelay / zones).
41#[derive(Debug, Clone, Default, Serialize, Deserialize)]
42pub struct DistanceRelaySettings {
43 /// CIM mRID.
44 pub mrid: String,
45 /// Relay name.
46 pub name: String,
47 /// Forward reach (Ohm).
48 pub forward_reach_ohm: Option<f64>,
49 /// Forward blind reach (Ohm).
50 pub forward_blind_ohm: Option<f64>,
51 /// Backward/reverse reach (Ohm).
52 pub backward_reach_ohm: Option<f64>,
53 /// Backward blind reach (Ohm).
54 pub backward_blind_ohm: Option<f64>,
55 /// MHO characteristic angle (degrees).
56 pub mho_angle_deg: Option<f64>,
57 /// Z0/Z1 compensation ratio.
58 pub zero_seq_rx_ratio: Option<f64>,
59 /// Zero-sequence forward reach (Ohm).
60 pub zero_seq_reach_ohm: Option<f64>,
61 /// Bus where CTs/VTs are located.
62 pub bus: Option<u32>,
63 /// Protected switch mRID.
64 pub protected_switch_mrid: Option<String>,
65}
66
67/// A single auto-reclose shot.
68#[derive(Debug, Clone, Default, Serialize, Deserialize)]
69pub struct RecloseShot {
70 /// Shot number (1-based).
71 pub step: u32,
72 /// Reclose delay (s).
73 pub delay_s: f64,
74}
75
76/// Auto-reclose sequence for a breaker.
77#[derive(Debug, Clone, Default, Serialize, Deserialize)]
78pub struct RecloseSequenceData {
79 /// Protected switch/breaker mRID.
80 pub protected_switch_mrid: String,
81 /// Ordered reclose shots.
82 pub shots: Vec<RecloseShot>,
83}
84
85/// Synchrocheck relay settings (IEC 61970-302 SynchrocheckRelay).
86#[derive(Debug, Clone, Default, Serialize, Deserialize)]
87pub struct SynchrocheckSettings {
88 /// CIM mRID.
89 pub mrid: String,
90 /// Relay name.
91 pub name: String,
92 /// Maximum angle difference (degrees).
93 pub max_angle_diff_deg: Option<f64>,
94 /// Maximum frequency difference (Hz).
95 pub max_freq_diff_hz: Option<f64>,
96 /// Maximum voltage magnitude difference (pu).
97 pub max_volt_diff_pu: Option<f64>,
98 /// Bus where relay is located.
99 pub bus: Option<u32>,
100 /// Protected switch mRID.
101 pub protected_switch_mrid: Option<String>,
102}
103
104/// Container for all protection equipment data.
105#[derive(Debug, Clone, Default, Serialize, Deserialize)]
106pub struct ProtectionData {
107 /// Overcurrent relays.
108 pub current_relays: Vec<CurrentRelaySettings>,
109 /// Distance/impedance relays.
110 pub distance_relays: Vec<DistanceRelaySettings>,
111 /// Auto-reclose sequences.
112 pub reclose_sequences: Vec<RecloseSequenceData>,
113 /// Synchrocheck relays.
114 pub synchrocheck_relays: Vec<SynchrocheckSettings>,
115}
116
117impl ProtectionData {
118 /// Returns true if no protection equipment has been loaded.
119 pub fn is_empty(&self) -> bool {
120 self.current_relays.is_empty()
121 && self.distance_relays.is_empty()
122 && self.reclose_sequences.is_empty()
123 && self.synchrocheck_relays.is_empty()
124 }
125}