sim_lib_interference_solve/
field.rs1use crate::{ReferenceSolveError, complex::Complex64};
4
5#[derive(Clone, Debug, PartialEq)]
7pub enum HostPhasorFieldError {
8 ZeroDimension {
10 axis: &'static str,
12 },
13 ShapeMismatch {
15 rows: usize,
17 columns: usize,
19 real_len: usize,
21 imaginary_len: usize,
23 },
24 NonFinite {
26 component: &'static str,
28 index: usize,
30 value: f64,
32 },
33}
34
35#[derive(Clone, Debug, PartialEq)]
40pub struct HostPhasorField {
41 rows: usize,
42 columns: usize,
43 real: Vec<f64>,
44 imaginary: Vec<f64>,
45}
46
47impl HostPhasorField {
48 pub fn from_component_planes(
54 rows: usize,
55 columns: usize,
56 real: Vec<f64>,
57 imaginary: Vec<f64>,
58 ) -> Result<Self, HostPhasorFieldError> {
59 if rows == 0 {
60 return Err(HostPhasorFieldError::ZeroDimension { axis: "rows" });
61 }
62 if columns == 0 {
63 return Err(HostPhasorFieldError::ZeroDimension { axis: "columns" });
64 }
65 let Some(cells) = rows.checked_mul(columns) else {
66 return Err(HostPhasorFieldError::ShapeMismatch {
67 rows,
68 columns,
69 real_len: real.len(),
70 imaginary_len: imaginary.len(),
71 });
72 };
73 if real.len() != cells || imaginary.len() != cells {
74 return Err(HostPhasorFieldError::ShapeMismatch {
75 rows,
76 columns,
77 real_len: real.len(),
78 imaginary_len: imaginary.len(),
79 });
80 }
81 for (component, values) in [("real", &real), ("imaginary", &imaginary)] {
82 if let Some((index, value)) = values
83 .iter()
84 .copied()
85 .enumerate()
86 .find(|(_, value)| !value.is_finite())
87 {
88 return Err(HostPhasorFieldError::NonFinite {
89 component,
90 index,
91 value,
92 });
93 }
94 }
95 Ok(Self {
96 rows,
97 columns,
98 real,
99 imaginary,
100 })
101 }
102
103 pub(crate) fn try_zeroed(rows: usize, columns: usize) -> Result<Self, ReferenceSolveError> {
104 let cells = rows
105 .checked_mul(columns)
106 .expect("SamplingPlane has already checked rows * columns");
107 let real = zeroed_component("real", cells)?;
108 let imaginary = zeroed_component("imaginary", cells)?;
109 Ok(Self {
110 rows,
111 columns,
112 real,
113 imaginary,
114 })
115 }
116
117 pub(crate) fn set_index(&mut self, index: usize, value: Complex64) {
118 let (real, imaginary) = value.components();
119 self.real[index] = real;
120 self.imaginary[index] = imaginary;
121 }
122
123 #[cfg(test)]
124 pub(crate) fn from_test_components(
125 rows: usize,
126 columns: usize,
127 real: Vec<f64>,
128 imaginary: Vec<f64>,
129 ) -> Self {
130 let cells = rows.checked_mul(columns).expect("test shape must fit");
131 assert_eq!(real.len(), cells);
132 assert_eq!(imaginary.len(), cells);
133 assert!(real.iter().chain(&imaginary).all(|value| value.is_finite()));
134 Self {
135 rows,
136 columns,
137 real,
138 imaginary,
139 }
140 }
141
142 pub fn rows(&self) -> usize {
144 self.rows
145 }
146
147 pub fn columns(&self) -> usize {
149 self.columns
150 }
151
152 pub fn len(&self) -> usize {
154 self.real.len()
155 }
156
157 pub fn is_empty(&self) -> bool {
162 self.real.is_empty()
163 }
164
165 pub fn real(&self) -> &[f64] {
167 &self.real
168 }
169
170 pub fn imaginary(&self) -> &[f64] {
172 &self.imaginary
173 }
174
175 pub fn cell(&self, row: usize, column: usize) -> Option<(f64, f64)> {
177 let index = row.checked_mul(self.columns)?.checked_add(column)?;
178 (row < self.rows && column < self.columns)
179 .then(|| Complex64::new(self.real[index], self.imaginary[index]).components())
180 }
181
182 pub fn into_component_planes(self) -> (usize, usize, Vec<f64>, Vec<f64>) {
184 (self.rows, self.columns, self.real, self.imaginary)
185 }
186}
187
188fn zeroed_component(
189 component: &'static str,
190 cells: usize,
191) -> Result<Vec<f64>, ReferenceSolveError> {
192 let mut values = Vec::new();
193 values
194 .try_reserve_exact(cells)
195 .map_err(|_| ReferenceSolveError::AllocationFailed { component, cells })?;
196 values.resize(cells, 0.0);
197 Ok(values)
198}
199
200#[cfg(test)]
201mod tests {
202 use super::HostPhasorField;
203
204 #[test]
205 fn component_planes_share_one_row_major_shape() {
206 let field = HostPhasorField {
207 rows: 2,
208 columns: 3,
209 real: vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0],
210 imaginary: vec![10.0, 11.0, 12.0, 13.0, 14.0, 15.0],
211 };
212
213 assert_eq!(field.rows(), 2);
214 assert_eq!(field.columns(), 3);
215 assert_eq!(field.len(), 6);
216 assert!(!field.is_empty());
217 assert_eq!(field.cell(1, 2), Some((5.0, 15.0)));
218 assert_eq!(field.cell(2, 0), None);
219 assert_eq!(field.cell(0, 3), None);
220 assert_eq!(field.real(), &[0.0, 1.0, 2.0, 3.0, 4.0, 5.0]);
221 assert_eq!(field.imaginary(), &[10.0, 11.0, 12.0, 13.0, 14.0, 15.0]);
222 }
223}