ringkernel_wavesim/simulation/
cell.rs1use super::AcousticParams;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum Direction {
8 North,
9 South,
10 East,
11 West,
12}
13
14impl Direction {
15 pub const ALL: [Direction; 4] = [
17 Direction::North,
18 Direction::South,
19 Direction::East,
20 Direction::West,
21 ];
22
23 pub fn opposite(self) -> Direction {
25 match self {
26 Direction::North => Direction::South,
27 Direction::South => Direction::North,
28 Direction::East => Direction::West,
29 Direction::West => Direction::East,
30 }
31 }
32}
33
34#[derive(Debug, Clone)]
39pub struct CellState {
40 pub x: u32,
42 pub y: u32,
44
45 pub pressure: f32,
47 pub pressure_prev: f32,
49
50 pub p_north: f32,
52 pub p_south: f32,
53 pub p_east: f32,
54 pub p_west: f32,
55
56 pub is_boundary: bool,
58 pub reflection_coeff: f32,
60}
61
62impl CellState {
63 pub fn new(x: u32, y: u32) -> Self {
65 Self {
66 x,
67 y,
68 pressure: 0.0,
69 pressure_prev: 0.0,
70 p_north: 0.0,
71 p_south: 0.0,
72 p_east: 0.0,
73 p_west: 0.0,
74 is_boundary: false,
75 reflection_coeff: 1.0,
76 }
77 }
78
79 pub fn kernel_id(&self) -> String {
81 format!("cell_{}_{}", self.x, self.y)
82 }
83
84 pub fn neighbor_id(&self, dir: Direction, width: u32, height: u32) -> Option<String> {
88 let (nx, ny) = match dir {
89 Direction::North if self.y > 0 => (self.x, self.y - 1),
90 Direction::South if self.y < height - 1 => (self.x, self.y + 1),
91 Direction::West if self.x > 0 => (self.x - 1, self.y),
92 Direction::East if self.x < width - 1 => (self.x + 1, self.y),
93 _ => return None,
94 };
95 Some(format!("cell_{}_{}", nx, ny))
96 }
97
98 pub fn step(&mut self, params: &AcousticParams) {
105 let c = params.courant_number();
106 let c2 = c * c;
107
108 let laplacian =
110 self.p_north + self.p_south + self.p_east + self.p_west - 4.0 * self.pressure;
111
112 let p_new = 2.0 * self.pressure - self.pressure_prev + c2 * laplacian;
114
115 let p_damped = p_new * (1.0 - params.damping);
117
118 let p_final = if self.is_boundary {
120 p_damped * self.reflection_coeff
121 } else {
122 p_damped
123 };
124
125 self.pressure_prev = self.pressure;
127 self.pressure = p_final;
128 }
129
130 pub fn inject_impulse(&mut self, amplitude: f32) {
132 self.pressure += amplitude;
133 }
134
135 pub fn reset(&mut self) {
137 self.pressure = 0.0;
138 self.pressure_prev = 0.0;
139 self.p_north = 0.0;
140 self.p_south = 0.0;
141 self.p_east = 0.0;
142 self.p_west = 0.0;
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149
150 #[test]
151 fn test_cell_state_new() {
152 let cell = CellState::new(5, 3);
153 assert_eq!(cell.x, 5);
154 assert_eq!(cell.y, 3);
155 assert_eq!(cell.pressure, 0.0);
156 assert!(!cell.is_boundary);
157 }
158
159 #[test]
160 fn test_kernel_id() {
161 let cell = CellState::new(5, 3);
162 assert_eq!(cell.kernel_id(), "cell_5_3");
163 }
164
165 #[test]
166 fn test_neighbor_id() {
167 let cell = CellState::new(5, 5);
168 assert_eq!(
169 cell.neighbor_id(Direction::North, 10, 10),
170 Some("cell_5_4".to_string())
171 );
172 assert_eq!(
173 cell.neighbor_id(Direction::South, 10, 10),
174 Some("cell_5_6".to_string())
175 );
176 assert_eq!(
177 cell.neighbor_id(Direction::East, 10, 10),
178 Some("cell_6_5".to_string())
179 );
180 assert_eq!(
181 cell.neighbor_id(Direction::West, 10, 10),
182 Some("cell_4_5".to_string())
183 );
184 }
185
186 #[test]
187 fn test_neighbor_id_at_boundary() {
188 let cell = CellState::new(0, 0);
189 assert_eq!(cell.neighbor_id(Direction::North, 10, 10), None);
190 assert_eq!(cell.neighbor_id(Direction::West, 10, 10), None);
191 assert!(cell.neighbor_id(Direction::South, 10, 10).is_some());
192 assert!(cell.neighbor_id(Direction::East, 10, 10).is_some());
193 }
194
195 #[test]
196 fn test_impulse_injection() {
197 let mut cell = CellState::new(0, 0);
198 cell.inject_impulse(0.5);
199 assert_eq!(cell.pressure, 0.5);
200 cell.inject_impulse(0.3);
201 assert_eq!(cell.pressure, 0.8);
202 }
203
204 #[test]
205 fn test_reset() {
206 let mut cell = CellState::new(0, 0);
207 cell.pressure = 1.0;
208 cell.pressure_prev = 0.5;
209 cell.p_north = 0.2;
210 cell.reset();
211 assert_eq!(cell.pressure, 0.0);
212 assert_eq!(cell.pressure_prev, 0.0);
213 assert_eq!(cell.p_north, 0.0);
214 }
215}