Skip to main content

laddu_physics/
quantum.rs

1//! Quantum-number helpers and discrete analysis enums.
2
3mod types;
4pub use types::*;
5
6mod state;
7pub use state::*;
8
9mod rules;
10pub use rules::*;
11
12/// Curated particle-property definitions for commonly used particles.
13pub mod builtin;
14
15/// Shorthand macro for constructing a total angular momentum [`J`].
16#[allow(unused_macros)]
17#[macro_export]
18macro_rules! j {
19    ($n:literal / 2) => {
20        $crate::quantum::J::half($n)
21    };
22    ($n:literal) => {
23        $crate::quantum::J::int($n)
24    };
25    ($($bad:tt)*) => {
26        compile_error!("expected j!(N) or j!(N/2) where N is an integer literal");
27    };
28}
29/// Shorthand macro for constructing a spin [`S`](`crate::quantum::J`).
30#[allow(unused_macros)]
31#[macro_export]
32macro_rules! s {
33    ($n:literal / 2) => {
34        $crate::quantum::S::half($n)
35    };
36    ($n:literal) => {
37        $crate::quantum::S::int($n)
38    };
39    ($($bad:tt)*) => {
40        compile_error!("expected s!(N) or s!(N/2) where N is an integer literal");
41    };
42}
43/// Shorthand macro for constructing an angular momentum projection [`M`].
44#[allow(unused_macros)]
45#[macro_export]
46macro_rules! m {
47    ($n:literal / 2) => {
48        $crate::quantum::M::half($n)
49    };
50    (- $n:literal / 2) => {
51        $crate::quantum::M::half(-$n)
52    };
53    ($n:literal) => {
54        $crate::quantum::M::int($n)
55    };
56    (- $n:literal) => {
57        $crate::quantum::M::int(-$n)
58    };
59    ($($bad:tt)*) => {
60        compile_error!(
61            "expected m!(N), m!(-N), m!(N/2), or m!(-N/2) where N is an integer literal"
62        );
63    };
64}
65/// Shorthand macro for constructing an orbital angular momentum [`L`].
66#[allow(unused_macros)]
67#[macro_export]
68macro_rules! l {
69    ($n:literal) => {
70        $crate::quantum::L::int($n)
71    };
72    ($($bad:tt)*) => {
73        compile_error!("expected l!(N) where N is an integer literal");
74    };
75}
76
77#[cfg(test)]
78mod tests {
79    use std::str::FromStr;
80
81    use super::*;
82
83    #[test]
84    fn check_angular_momentum_macros() {
85        assert_eq!(J::int(1), j!(1));
86        assert_eq!(J::half(1), j!(1 / 2));
87        assert_eq!(S::int(1), s!(1));
88        assert_eq!(S::half(1), s!(1 / 2));
89        assert_eq!(M::int(1), m!(1));
90        assert_eq!(M::half(1), m!(1 / 2));
91        assert_eq!(M::int(-1), m!(-1));
92        assert_eq!(M::half(-1), m!(-1 / 2));
93        assert_eq!(L::int(1), l!(1));
94    }
95
96    #[test]
97    fn spin_state_accepts_integer_and_half_integer_values() {
98        let spin_one = j!(1);
99        let spin_half = j!(1 / 2);
100        assert_eq!(
101            SpinState::new(spin_one, m!(0))
102                .unwrap()
103                .projection()
104                .doubled(),
105            0
106        );
107        assert_eq!(
108            SpinState::new(spin_half, m!(-1 / 2))
109                .unwrap()
110                .projection()
111                .doubled(),
112            -1
113        );
114    }
115
116    #[test]
117    fn spin_state_rejects_invalid_projection() {
118        let spin_one = j!(1);
119        assert!(SpinState::new(spin_one, m!(4 / 2)).is_err());
120        assert!(SpinState::new(spin_one, m!(1 / 2)).is_err());
121    }
122
123    #[test]
124    fn angular_momenta_return_projection_values() {
125        assert_eq!(j!(1).projections(), vec![m!(-1), m!(0), m!(1)]);
126        assert_eq!(
127            j!(3 / 2).projections(),
128            vec![m!(-3 / 2), m!(-1 / 2), m!(1 / 2), m!(3 / 2)]
129        );
130        assert_eq!(l!(1).projections(), j!(1).projections());
131    }
132
133    #[test]
134    fn enum_displays() {
135        assert_eq!(format!("{}", Reflectivity::Positive), "+");
136        assert_eq!(format!("{}", Reflectivity::Negative), "-");
137        assert_eq!(format!("{}", MandelstamChannel::S), "s");
138        assert_eq!(format!("{}", MandelstamChannel::T), "t");
139        assert_eq!(format!("{}", MandelstamChannel::U), "u");
140    }
141
142    #[test]
143    fn enum_from_str() {
144        assert_eq!(Reflectivity::from_str("+").unwrap(), Reflectivity::Positive);
145        assert_eq!(
146            Reflectivity::from_str("pos").unwrap(),
147            Reflectivity::Positive
148        );
149        assert_eq!(
150            Reflectivity::from_str("plus").unwrap(),
151            Reflectivity::Positive
152        );
153        assert_eq!(
154            Reflectivity::from_str("Positive").unwrap(),
155            Reflectivity::Positive
156        );
157        assert_eq!(Reflectivity::from_str("-").unwrap(), Reflectivity::Negative);
158        assert_eq!(
159            Reflectivity::from_str("minus").unwrap(),
160            Reflectivity::Negative
161        );
162        assert_eq!(
163            Reflectivity::from_str("neg").unwrap(),
164            Reflectivity::Negative
165        );
166        assert_eq!(
167            Reflectivity::from_str("Negative").unwrap(),
168            Reflectivity::Negative
169        );
170        assert_eq!(
171            MandelstamChannel::from_str("S").unwrap(),
172            MandelstamChannel::S
173        );
174        assert_eq!(
175            MandelstamChannel::from_str("s").unwrap(),
176            MandelstamChannel::S
177        );
178        assert_eq!(
179            MandelstamChannel::from_str("T").unwrap(),
180            MandelstamChannel::T
181        );
182        assert_eq!(
183            MandelstamChannel::from_str("t").unwrap(),
184            MandelstamChannel::T
185        );
186        assert_eq!(
187            MandelstamChannel::from_str("U").unwrap(),
188            MandelstamChannel::U
189        );
190        assert_eq!(
191            MandelstamChannel::from_str("u").unwrap(),
192            MandelstamChannel::U
193        );
194    }
195}