1use std::collections::HashMap;
2
3use crate::Float;
4
5#[derive(Clone, Debug)]
6pub struct Block {
7 pub imax: usize,
8 pub jmax: usize,
9 pub kmax: usize, pub x: Vec<Float>, pub y: Vec<Float>,
12 pub z: Vec<Float>,
13}
14
15#[derive(Clone, Debug)]
17pub struct FaceData {
18 pub x: Vec<Float>,
19 pub y: Vec<Float>,
20 pub z: Vec<Float>,
21 pub dims: (usize, usize),
23}
24
25impl Block {
26 pub fn new(
27 imax: usize,
28 jmax: usize,
29 kmax: usize,
30 x: Vec<Float>,
31 y: Vec<Float>,
32 z: Vec<Float>,
33 ) -> Self {
34 let n = imax * jmax * kmax;
35 assert_eq!(x.len(), n);
36 assert_eq!(y.len(), n);
37 assert_eq!(z.len(), n);
38 Self {
39 imax,
40 jmax,
41 kmax,
42 x,
43 y,
44 z,
45 }
46 }
47
48 #[inline]
50 pub fn npoints(&self) -> usize {
51 self.imax * self.jmax * self.kmax
52 }
53
54 #[inline]
56 pub fn idx(&self, i: usize, j: usize, k: usize) -> usize {
57 debug_assert!(i < self.imax && j < self.jmax && k < self.kmax);
59 (k * self.jmax + j) * self.imax + i
60 }
61
62 #[inline]
64 pub fn xyz(&self, i: usize, j: usize, k: usize) -> (Float, Float, Float) {
65 let idx = self.idx(i, j, k);
66 (self.x[idx], self.y[idx], self.z[idx])
67 }
68
69 #[inline]
71 pub fn x_at(&self, i: usize, j: usize, k: usize) -> Float {
72 self.x[self.idx(i, j, k)]
73 }
74
75 #[inline]
77 pub fn y_at(&self, i: usize, j: usize, k: usize) -> Float {
78 self.y[self.idx(i, j, k)]
79 }
80
81 #[inline]
83 pub fn z_at(&self, i: usize, j: usize, k: usize) -> Float {
84 self.z[self.idx(i, j, k)]
85 }
86
87 #[inline]
89 pub fn x_slice(&self) -> &[Float] {
90 &self.x
91 }
92
93 #[inline]
95 pub fn y_slice(&self) -> &[Float] {
96 &self.y
97 }
98
99 #[inline]
101 pub fn z_slice(&self) -> &[Float] {
102 &self.z
103 }
104
105 #[inline]
107 pub fn axis_slice(&self, axis_idx: usize) -> &[Float] {
108 match axis_idx {
109 0 => &self.x,
110 1 => &self.y,
111 _ => &self.z,
112 }
113 }
114
115 #[inline]
116 pub fn centroid(&self) -> (Float, Float, Float) {
117 let n = self.npoints() as Float;
118 let sum_x: Float = self.x.iter().sum();
119 let sum_y: Float = self.y.iter().sum();
120 let sum_z: Float = self.z.iter().sum();
121 (sum_x / n, sum_y / n, sum_z / n)
122 }
123
124 pub fn print_xyz(&self, i: usize, j: usize, k: usize) {
126 let (x, y, z) = self.xyz(i, j, k);
127 println!("XYZ at (i={i}, j={j}, k={k}) is ({x:.6}, {y:.6}, {z:.6})");
128 }
129
130 pub fn shifted(&self, amount: Float, axis: char) -> Block {
131 let mut new = self.clone();
132 new.shift_in_place(amount, axis);
133 new
134 }
135
136 pub fn shift_in_place(&mut self, amount: Float, axis: char) {
137 if amount == 0.0 {
138 return;
139 }
140 match axis.to_ascii_lowercase() {
141 'x' => {
142 for v in &mut self.x {
143 *v += amount;
144 }
145 }
146 'y' => {
147 for v in &mut self.y {
148 *v += amount;
149 }
150 }
151 'z' => {
152 for v in &mut self.z {
153 *v += amount;
154 }
155 }
156 _ => {}
157 }
158 }
159
160 #[inline]
162 pub fn size(&self) -> usize {
163 self.npoints()
164 }
165
166 pub fn scale(&mut self, factor: Float) {
168 for v in &mut self.x {
169 *v *= factor;
170 }
171 for v in &mut self.y {
172 *v *= factor;
173 }
174 for v in &mut self.z {
175 *v *= factor;
176 }
177 }
178
179 pub fn scaled(&self, factor: Float) -> Block {
181 let mut new = self.clone();
182 new.scale(factor);
183 new
184 }
185
186 pub fn cylindrical(&self, rotation_axis: char) -> (Vec<Float>, Vec<Float>) {
192 let n = self.npoints();
193 let mut r = Vec::with_capacity(n);
194 let mut theta = Vec::with_capacity(n);
195 for idx in 0..n {
196 let (a, b) = match rotation_axis.to_ascii_lowercase() {
197 'x' => (self.y[idx], self.z[idx]),
198 'y' => (self.z[idx], self.x[idx]),
199 'z' => (self.x[idx], self.y[idx]),
200 _ => (self.y[idx], self.z[idx]), };
202 r.push((a * a + b * b).sqrt());
203 theta.push(a.atan2(b));
204 }
205 (r, theta)
206 }
207
208 pub fn cell_volumes(&self) -> Vec<Float> {
216 let (ni, nj, nk) = (self.imax, self.jmax, self.kmax);
217 let n = ni * nj * nk;
218 let idx = |i: usize, j: usize, k: usize| -> usize { (k * nj + j) * ni + i };
219
220 let mut a = vec![vec![0.0; n]; 9];
222
223 for k in 1..nk {
225 for j in 1..nj {
226 for i in 0..ni {
227 let dx1 = self.x[idx(i, j, k - 1)] - self.x[idx(i, j - 1, k)];
228 let dy1 = self.y[idx(i, j, k - 1)] - self.y[idx(i, j - 1, k)];
229 let dz1 = self.z[idx(i, j, k - 1)] - self.z[idx(i, j - 1, k)];
230
231 let dx2 = self.x[idx(i, j, k)] - self.x[idx(i, j - 1, k - 1)];
232 let dy2 = self.y[idx(i, j, k)] - self.y[idx(i, j - 1, k - 1)];
233 let dz2 = self.z[idx(i, j, k)] - self.z[idx(i, j - 1, k - 1)];
234
235 let id = idx(i, j, k);
236 a[0][id] = (dy1 * dz2 - dz1 * dy2) * 0.5;
237 a[1][id] = (dz1 * dx2 - dx1 * dz2) * 0.5;
238 a[2][id] = (dx1 * dy2 - dy1 * dx2) * 0.5;
239 }
240 }
241 }
242
243 for k in 1..nk {
245 for j in 0..nj {
246 for i in 1..ni {
247 let dx1 = self.x[idx(i, j, k)] - self.x[idx(i - 1, j, k - 1)];
248 let dy1 = self.y[idx(i, j, k)] - self.y[idx(i - 1, j, k - 1)];
249 let dz1 = self.z[idx(i, j, k)] - self.z[idx(i - 1, j, k - 1)];
250
251 let dx2 = self.x[idx(i, j, k - 1)] - self.x[idx(i - 1, j, k)];
252 let dy2 = self.y[idx(i, j, k - 1)] - self.y[idx(i - 1, j, k)];
253 let dz2 = self.z[idx(i, j, k - 1)] - self.z[idx(i - 1, j, k)];
254
255 let id = idx(i, j, k);
256 a[3][id] = (dy1 * dz2 - dz1 * dy2) * 0.5;
257 a[4][id] = (dz1 * dx2 - dx1 * dz2) * 0.5;
258 a[5][id] = (dx1 * dy2 - dy1 * dx2) * 0.5;
259 }
260 }
261 }
262
263 for k in 0..nk {
265 for j in 1..nj {
266 for i in 1..ni {
267 let dx1 = self.x[idx(i, j, k)] - self.x[idx(i - 1, j - 1, k)];
268 let dy1 = self.y[idx(i, j, k)] - self.y[idx(i - 1, j - 1, k)];
269 let dz1 = self.z[idx(i, j, k)] - self.z[idx(i - 1, j - 1, k)];
270
271 let dx2 = self.x[idx(i - 1, j, k)] - self.x[idx(i, j - 1, k)];
272 let dy2 = self.y[idx(i - 1, j, k)] - self.y[idx(i, j - 1, k)];
273 let dz2 = self.z[idx(i - 1, j, k)] - self.z[idx(i, j - 1, k)];
274
275 let id = idx(i, j, k);
276 a[6][id] = (dy1 * dz2 - dz1 * dy2) * 0.5;
277 a[7][id] = (dz1 * dx2 - dx1 * dz2) * 0.5;
278 a[8][id] = (dx1 * dy2 - dy1 * dx2) * 0.5;
279 }
280 }
281 }
282
283 let mut v = vec![0.0; n];
285 for k in 1..nk {
286 for j in 1..nj {
287 for i in 1..ni {
288 let mut cf = [[0.0; 3]; 6];
290 cf[0][0] = self.x[idx(i - 1, j - 1, k - 1)]
292 + self.x[idx(i - 1, j - 1, k)]
293 + self.x[idx(i - 1, j, k - 1)]
294 + self.x[idx(i - 1, j, k)];
295 cf[0][1] = self.y[idx(i - 1, j - 1, k - 1)]
296 + self.y[idx(i - 1, j - 1, k)]
297 + self.y[idx(i - 1, j, k - 1)]
298 + self.y[idx(i - 1, j, k)];
299 cf[0][2] = self.z[idx(i - 1, j - 1, k - 1)]
300 + self.z[idx(i - 1, j - 1, k)]
301 + self.z[idx(i - 1, j, k - 1)]
302 + self.z[idx(i - 1, j, k)];
303 cf[1][0] = self.x[idx(i, j - 1, k - 1)]
305 + self.x[idx(i, j - 1, k)]
306 + self.x[idx(i, j, k - 1)]
307 + self.x[idx(i, j, k)];
308 cf[1][1] = self.y[idx(i, j - 1, k - 1)]
309 + self.y[idx(i, j - 1, k)]
310 + self.y[idx(i, j, k - 1)]
311 + self.y[idx(i, j, k)];
312 cf[1][2] = self.z[idx(i, j - 1, k - 1)]
313 + self.z[idx(i, j - 1, k)]
314 + self.z[idx(i, j, k - 1)]
315 + self.z[idx(i, j, k)];
316 cf[2][0] = self.x[idx(i - 1, j - 1, k - 1)]
318 + self.x[idx(i - 1, j - 1, k)]
319 + self.x[idx(i, j - 1, k - 1)]
320 + self.x[idx(i, j - 1, k)];
321 cf[2][1] = self.y[idx(i - 1, j - 1, k - 1)]
322 + self.y[idx(i - 1, j - 1, k)]
323 + self.y[idx(i, j - 1, k - 1)]
324 + self.y[idx(i, j - 1, k)];
325 cf[2][2] = self.z[idx(i - 1, j - 1, k - 1)]
326 + self.z[idx(i - 1, j - 1, k)]
327 + self.z[idx(i, j - 1, k - 1)]
328 + self.z[idx(i, j - 1, k)];
329 cf[3][0] = self.x[idx(i - 1, j, k - 1)]
331 + self.x[idx(i - 1, j, k)]
332 + self.x[idx(i, j, k - 1)]
333 + self.x[idx(i, j, k)];
334 cf[3][1] = self.y[idx(i - 1, j, k - 1)]
335 + self.y[idx(i - 1, j, k)]
336 + self.y[idx(i, j, k - 1)]
337 + self.y[idx(i, j, k)];
338 cf[3][2] = self.z[idx(i - 1, j, k - 1)]
339 + self.z[idx(i - 1, j, k)]
340 + self.z[idx(i, j, k - 1)]
341 + self.z[idx(i, j, k)];
342 cf[4][0] = self.x[idx(i - 1, j - 1, k - 1)]
344 + self.x[idx(i - 1, j, k - 1)]
345 + self.x[idx(i, j - 1, k - 1)]
346 + self.x[idx(i, j, k - 1)];
347 cf[4][1] = self.y[idx(i - 1, j - 1, k - 1)]
348 + self.y[idx(i - 1, j, k - 1)]
349 + self.y[idx(i, j - 1, k - 1)]
350 + self.y[idx(i, j, k - 1)];
351 cf[4][2] = self.z[idx(i - 1, j - 1, k - 1)]
352 + self.z[idx(i - 1, j, k - 1)]
353 + self.z[idx(i, j - 1, k - 1)]
354 + self.z[idx(i, j, k - 1)];
355 cf[5][0] = self.x[idx(i - 1, j - 1, k)]
357 + self.x[idx(i - 1, j, k)]
358 + self.x[idx(i, j - 1, k)]
359 + self.x[idx(i, j, k)];
360 cf[5][1] = self.y[idx(i - 1, j - 1, k)]
361 + self.y[idx(i - 1, j, k)]
362 + self.y[idx(i, j - 1, k)]
363 + self.y[idx(i, j, k)];
364 cf[5][2] = self.z[idx(i - 1, j - 1, k)]
365 + self.z[idx(i - 1, j, k)]
366 + self.z[idx(i, j - 1, k)]
367 + self.z[idx(i, j, k)];
368
369 let mut vol12 = 0.0;
370 for nn in 0..2usize {
371 let sign = if nn == 0 { -1.0 } else { 1.0 };
372 for l in 0..3usize {
373 vol12 += sign
375 * (cf[nn][l] * a[l][idx(i - 1 + nn, j, k)]
376 + cf[2 + nn][l] * a[3 + l][idx(i, j - 1 + nn, k)]
377 + cf[4 + nn][l] * a[6 + l][idx(i, j, k - 1 + nn)]);
378 }
379 }
380 v[idx(i, j, k)] = vol12 / 12.0;
381 }
382 }
383 }
384 v
385 }
386
387 pub fn get_faces(&self) -> HashMap<&'static str, FaceData> {
393 let mut map = HashMap::with_capacity(6);
394
395 let extract = |fix_axis: usize, fix_val: usize| -> FaceData {
397 let (nu, nv) = match fix_axis {
398 0 => (self.jmax, self.kmax), 1 => (self.imax, self.kmax), _ => (self.imax, self.jmax), };
402 let cap = nu * nv;
403 let mut xf = Vec::with_capacity(cap);
404 let mut yf = Vec::with_capacity(cap);
405 let mut zf = Vec::with_capacity(cap);
406 for v in 0..nv {
407 for u in 0..nu {
408 let (i, j, k) = match fix_axis {
409 0 => (fix_val, u, v),
410 1 => (u, fix_val, v),
411 _ => (u, v, fix_val),
412 };
413 let id = self.idx(i, j, k);
414 xf.push(self.x[id]);
415 yf.push(self.y[id]);
416 zf.push(self.z[id]);
417 }
418 }
419 FaceData {
420 x: xf,
421 y: yf,
422 z: zf,
423 dims: (nu, nv),
424 }
425 };
426
427 map.insert("imin", extract(0, 0));
428 map.insert("imax", extract(0, self.imax - 1));
429 map.insert("jmin", extract(1, 0));
430 map.insert("jmax", extract(1, self.jmax - 1));
431 map.insert("kmin", extract(2, 0));
432 map.insert("kmax", extract(2, self.kmax - 1));
433 map
434 }
435
436 pub fn sub_block(
438 &self,
439 i_range: std::ops::RangeInclusive<usize>,
440 j_range: std::ops::RangeInclusive<usize>,
441 k_range: std::ops::RangeInclusive<usize>,
442 ) -> Block {
443 let ni = i_range.end() - i_range.start() + 1;
444 let nj = j_range.end() - j_range.start() + 1;
445 let nk = k_range.end() - k_range.start() + 1;
446 let cap = ni * nj * nk;
447 let mut x = Vec::with_capacity(cap);
448 let mut y = Vec::with_capacity(cap);
449 let mut z = Vec::with_capacity(cap);
450 for k in k_range {
451 for j in j_range.clone() {
452 for i in i_range.clone() {
453 let id = self.idx(i, j, k);
454 x.push(self.x[id]);
455 y.push(self.y[id]);
456 z.push(self.z[id]);
457 }
458 }
459 }
460 Block::new(ni, nj, nk, x, y, z)
461 }
462}