surge_network/network/asset.rs
1// SPDX-License-Identifier: LicenseRef-PolyForm-Noncommercial-1.0.0
2//! Physical asset and wire information types from CIM IEC 61968-11 Asset package.
3//!
4//! These types store conductor properties, cable construction details, tower
5//! geometry, transformer nameplate data, and general asset metadata parsed from
6//! CGMES WireInfo / CableInfo / WireSpacingInfo / TransformerTankInfo classes.
7//!
8//! Future use: Carson's equation / Ametani impedance calculation from wire geometry.
9
10use std::collections::HashMap;
11
12use chrono::{DateTime, Utc};
13use serde::{Deserialize, Serialize};
14
15/// Physical conductor properties from CIM WireInfo / OverheadWireInfo.
16#[derive(Debug, Clone, Default, Serialize, Deserialize)]
17pub struct WireProperties {
18 /// Human-readable name (from IdentifiedObject.name).
19 pub name: String,
20 /// AC resistance at 75 deg C (Ohm/km).
21 pub r_ac75_ohm_per_km: Option<f64>,
22 /// DC resistance at 20 deg C (Ohm/km).
23 pub r_dc20_ohm_per_km: Option<f64>,
24 /// Geometric Mean Radius (m).
25 pub gmr_m: Option<f64>,
26 /// Conductor radius (m).
27 pub radius_m: Option<f64>,
28 /// Size designation (e.g., "795 kcmil", "Drake").
29 pub size_description: Option<String>,
30 /// WireMaterialKind: copper, aluminum, steel, acsr, etc.
31 pub material: Option<String>,
32 /// Number of strands.
33 pub strand_count: Option<u32>,
34 /// Number of steel core strands.
35 pub core_strand_count: Option<u32>,
36 /// Ampacity (A).
37 pub rated_current_a: Option<f64>,
38}
39
40/// Cable-specific properties from CIM CableInfo / ConcentricNeutralCableInfo / TapeShieldCableInfo.
41#[derive(Debug, Clone, Default, Serialize, Deserialize)]
42pub struct CableProperties {
43 /// Base wire properties inherited from WireInfo.
44 pub wire: WireProperties,
45 /// Rated temperature (deg C).
46 pub nominal_temperature_c: Option<f64>,
47 /// Insulation material (CableConstructionKind).
48 pub insulation_material: Option<String>,
49 /// Insulation thickness (mm).
50 pub insulation_thickness_mm: Option<f64>,
51 /// Outer jacket thickness (mm).
52 pub outer_jacket_thickness_mm: Option<f64>,
53 /// Shield material (CableShieldMaterialKind).
54 pub shield_material: Option<String>,
55 /// Diameter over insulation (mm).
56 pub diameter_over_insulation_mm: Option<f64>,
57 /// Diameter over jacket (mm).
58 pub diameter_over_jacket_mm: Option<f64>,
59 /// Diameter over screen (mm).
60 pub diameter_over_screen_mm: Option<f64>,
61 /// Whether strand fill is used.
62 pub is_strand_fill: Option<bool>,
63 // -- Concentric neutral cable fields --
64 /// Number of neutral strands (concentric neutral cable).
65 pub neutral_strand_count: Option<u32>,
66 /// GMR of neutral strand in meters (concentric neutral cable).
67 pub neutral_strand_gmr_m: Option<f64>,
68 /// Radius of neutral strand in meters (concentric neutral cable).
69 pub neutral_strand_radius_m: Option<f64>,
70 /// DC resistance of neutral at 20 deg C in Ohm/km (concentric neutral cable).
71 pub neutral_strand_rdc20_ohm_per_km: Option<f64>,
72 // -- Tape shield cable fields --
73 /// Tape thickness in mm (tape shield cable).
74 pub tape_thickness_mm: Option<f64>,
75 /// Tape lap percent overlap (tape shield cable).
76 pub tape_lap_percent: Option<f64>,
77}
78
79/// A single conductor position within a tower/spacing configuration.
80#[derive(Debug, Clone, Default, Serialize, Deserialize)]
81pub struct WirePosition {
82 /// Horizontal position from tower center (m).
83 pub x_m: f64,
84 /// Height above ground (m).
85 pub y_m: f64,
86 /// Phase assignment (A, B, C, N, s1, s2).
87 pub phase: Option<String>,
88 /// Ordering within the spacing.
89 pub sequence_number: u32,
90}
91
92/// Tower/spacing geometry for overhead or underground lines from CIM WireSpacingInfo.
93#[derive(Debug, Clone, Default, Serialize, Deserialize)]
94pub struct WireSpacing {
95 /// Human-readable name.
96 pub name: String,
97 /// Whether this is an underground cable spacing (vs overhead).
98 pub is_cable: bool,
99 /// Number of conductors per phase (bundle count).
100 pub phase_wire_count: u32,
101 /// Bundle spacing in meters.
102 pub phase_wire_spacing_m: Option<f64>,
103 /// Conductor positions (phase and neutral).
104 pub positions: Vec<WirePosition>,
105}
106
107/// Transformer nameplate data from CIM TransformerTankInfo / PowerTransformerInfo.
108#[derive(Debug, Clone, Default, Serialize, Deserialize)]
109pub struct TransformerInfoData {
110 /// Human-readable name.
111 pub name: String,
112 /// Winding information (one per TransformerEndInfo).
113 pub windings: Vec<TransformerWindingInfo>,
114 /// No-load (iron) loss in watts.
115 pub no_load_loss_w: Option<f64>,
116 /// Exciting current as percentage of rated current.
117 pub exciting_current_pct: Option<f64>,
118 /// Short-circuit (copper) loss in watts.
119 pub short_circuit_loss_w: Option<f64>,
120 /// Leakage impedance as percentage.
121 pub leakage_impedance_pct: Option<f64>,
122}
123
124/// Per-winding data from CIM TransformerEndInfo.
125#[derive(Debug, Clone, Default, Serialize, Deserialize)]
126pub struct TransformerWindingInfo {
127 /// Winding number (1, 2, 3).
128 pub end_number: u32,
129 /// Nameplate MVA.
130 pub rated_s_mva: Option<f64>,
131 /// Rated voltage (kV).
132 pub rated_u_kv: Option<f64>,
133 /// Winding resistance (Ohm).
134 pub r_ohm: Option<f64>,
135 /// Connection kind (Y, D, Yn, etc.).
136 pub connection_kind: Option<String>,
137 /// Insulation voltage (kV).
138 pub insulation_u_kv: Option<f64>,
139 /// Short-term emergency rating (MVA).
140 pub short_term_s_mva: Option<f64>,
141}
142
143/// General asset metadata from CIM Asset / ProductAssetModel.
144#[derive(Debug, Clone, Default, Serialize, Deserialize)]
145pub struct AssetMetadata {
146 /// Equipment mRID this asset record is associated with.
147 pub equipment_mrid: String,
148 /// Serial number.
149 pub serial_number: Option<String>,
150 /// Manufacturer name (from ProductAssetModel).
151 pub manufacturer: Option<String>,
152 /// Model number.
153 pub model_number: Option<String>,
154 /// Date of manufacture.
155 pub manufactured_date: Option<DateTime<Utc>>,
156 /// Installation date.
157 pub installation_date: Option<DateTime<Utc>>,
158 /// Retirement date.
159 pub retired_date: Option<DateTime<Utc>>,
160}
161
162/// Complete asset information container for the network.
163///
164/// Populated by the CGMES parser when Asset/WireInfo profile data is present.
165/// Keyed by CIM mRID for cross-reference with equipment objects.
166#[derive(Debug, Clone, Default, Serialize, Deserialize)]
167pub struct AssetCatalog {
168 /// Wire/conductor definitions keyed by CIM mRID.
169 pub wire_infos: HashMap<String, WireProperties>,
170 /// Cable definitions keyed by CIM mRID.
171 pub cable_infos: HashMap<String, CableProperties>,
172 /// Wire spacing/tower geometry keyed by CIM mRID.
173 pub wire_spacings: HashMap<String, WireSpacing>,
174 /// Transformer info keyed by CIM mRID.
175 pub transformer_infos: HashMap<String, TransformerInfoData>,
176 /// Asset metadata keyed by equipment mRID.
177 pub asset_metadata: HashMap<String, AssetMetadata>,
178}
179
180impl AssetCatalog {
181 /// Returns true if no asset data has been populated.
182 pub fn is_empty(&self) -> bool {
183 self.wire_infos.is_empty()
184 && self.cable_infos.is_empty()
185 && self.wire_spacings.is_empty()
186 && self.transformer_infos.is_empty()
187 && self.asset_metadata.is_empty()
188 }
189}