ak_core/geometry/
cell.rs

1use nalgebra::{Matrix3, Vector3};
2
3#[derive(Clone, Copy, Debug, PartialEq)]
4pub struct Cell {
5    // Rows are lattice vectors a, b, c (stored column-major internally by nalgebra)
6    pub m: Matrix3<f64>,
7}
8
9impl Cell {
10    pub fn new(cell: [[f64; 3]; 3]) -> Self {
11        Cell {
12            m: Matrix3::from_row_slice(cell.as_flattened()),
13        }
14    }
15
16    pub fn is_orthorhombic(&self) -> bool {
17        let eps = 1e-12;
18
19        // Subtract the diagonal part — remainder should be ~zero
20        let off_diagonal = self.m - Matrix3::from_diagonal(&self.m.diagonal());
21
22        // All off-diagonal elements are ~0
23        let is_diagonal = off_diagonal.abs().max() < eps;
24
25        // All diagonal elements are positive
26        let has_positive_diagonal = self.m.diagonal().iter().all(|&x| x > eps);
27
28        is_diagonal && has_positive_diagonal
29    }
30
31    pub fn a(&self) -> Vector3<f64> {
32        self.m.row(0).transpose()
33    }
34
35    pub fn b(&self) -> Vector3<f64> {
36        self.m.row(1).transpose()
37    }
38
39    pub fn c(&self) -> Vector3<f64> {
40        self.m.row(2).transpose()
41    }
42
43    pub fn reduced(&self, a: f64, b: f64, c: f64) -> Vector3<f64> {
44        self.m.transpose() * Vector3::new(a, b, c)
45    }
46}
47
48#[cfg(test)]
49mod tests {
50
51    use nalgebra::Vector3;
52
53    use crate::Cell;
54
55    #[test]
56    fn test_ortho() {
57        let cell = Cell::new([[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]]);
58        assert!(cell.is_orthorhombic())
59    }
60
61    #[test]
62    fn test_not_ortho() {
63        let cell = Cell::new([[10.0, 5.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]]);
64        assert!(!cell.is_orthorhombic())
65    }
66
67    #[test]
68    fn test_reduced_1() {
69        let cell = Cell::new([[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]]);
70        let result = cell.reduced(1.0, 0.0, 0.0);
71        let expected = Vector3::new(10.0, 0.0, 0.0);
72        assert_eq!(result, expected);
73    }
74
75    #[test]
76    fn test_reduced_2() {
77        let cell = Cell::new([[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]]);
78        let result = cell.reduced(0.0, 1.0, 0.0);
79        let expected = Vector3::new(0.0, 10.0, 0.0);
80        assert_eq!(result, expected);
81    }
82
83    #[test]
84    fn test_reduced_3() {
85        let cell = Cell::new([[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]]);
86        let result = cell.reduced(0.0, 0.0, 1.0);
87        let expected = Vector3::new(0.0, 0.0, 10.0);
88        assert_eq!(result, expected);
89    }
90
91    #[test]
92    fn test_reduced_4() {
93        let cell = Cell::new([[10.0, 5.0, 0.0], [5.0, 10.0, 0.0], [0.0, 0.0, 10.0]]);
94        let result = cell.reduced(0.5, 0.0, 0.0);
95        let expected = Vector3::new(5.0, 2.5, 0.0);
96        assert_eq!(result, expected);
97    }
98
99    #[test]
100    fn test_reduced_5() {
101        let cell = Cell::new([[10.0, 5.0, 0.0], [5.0, 10.0, 0.0], [0.0, 0.0, 10.0]]);
102        let result = cell.reduced(0.5, 0.5, 0.0);
103        let expected = Vector3::new(7.5, 7.5, 0.0);
104        assert_eq!(result, expected);
105    }
106
107    #[test]
108    fn test_cell_vectors() {
109        let cell = Cell::new([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]);
110
111        assert_eq!(cell.a(), Vector3::new(1.0, 2.0, 3.0));
112        assert_eq!(cell.b(), Vector3::new(4.0, 5.0, 6.0));
113        assert_eq!(cell.c(), Vector3::new(7.0, 8.0, 9.0));
114    }
115}