use crate::constants::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Nuclide {
Neutron,
Proton,
Deuterium,
Tritium,
Helium3,
Helium4,
Lithium7,
Beryllium7,
}
impl Nuclide {
pub fn mass_number(&self) -> u8 {
match self {
Nuclide::Neutron => 1,
Nuclide::Proton => 1,
Nuclide::Deuterium => 2,
Nuclide::Tritium => 3,
Nuclide::Helium3 => 3,
Nuclide::Helium4 => 4,
Nuclide::Lithium7 => 7,
Nuclide::Beryllium7 => 7,
}
}
pub fn binding_energy(&self) -> f64 {
match self {
Nuclide::Neutron => 0.0,
Nuclide::Proton => 0.0,
Nuclide::Deuterium => 2.224,
Nuclide::Tritium => 8.482,
Nuclide::Helium3 => 7.718,
Nuclide::Helium4 => 28.296,
Nuclide::Lithium7 => 39.245,
Nuclide::Beryllium7 => 37.600,
}
}
pub fn symbol(&self) -> &'static str {
match self {
Nuclide::Neutron => "n",
Nuclide::Proton => "p",
Nuclide::Deuterium => "²H",
Nuclide::Tritium => "³H",
Nuclide::Helium3 => "³He",
Nuclide::Helium4 => "⁴He",
Nuclide::Lithium7 => "⁷Li",
Nuclide::Beryllium7 => "⁷Be",
}
}
pub fn latex(&self) -> &'static str {
match self {
Nuclide::Neutron => "n",
Nuclide::Proton => "p",
Nuclide::Deuterium => r"^{2}\mathrm{H}",
Nuclide::Tritium => r"^{3}\mathrm{H}",
Nuclide::Helium3 => r"^{3}\mathrm{He}",
Nuclide::Helium4 => r"^{4}\mathrm{He}",
Nuclide::Lithium7 => r"^{7}\mathrm{Li}",
Nuclide::Beryllium7 => r"^{7}\mathrm{Be}",
}
}
}
#[derive(Debug, Clone)]
pub struct Reaction {
pub reactants: Vec<Nuclide>,
pub products: Vec<Nuclide>,
pub q_value: f64, pub label: String,
}
impl Reaction {
pub fn new(reactants: Vec<Nuclide>, products: Vec<Nuclide>, label: &str) -> Self {
let be_products: f64 = products.iter().map(|n| n.binding_energy()).sum();
let be_reactants: f64 = reactants.iter().map(|n| n.binding_energy()).sum();
let q_value = be_products - be_reactants;
Reaction {
reactants,
products,
q_value,
label: label.to_string(),
}
}
pub fn rate_coefficient(&self, temp_k: f64) -> f64 {
let t9 = temp_k / 1e9;
let scale = 1e-20;
let base_rate = match self.label.as_str() {
"p(n,γ)d" => {
4.742e-4 * (1.0 / t9)
},
"d(p,γ)³He" => {
2.24e3 * t9.powf(-2.0/3.0) * (-3.720 / t9.powf(1.0/3.0)).exp()
* (1.0 + 0.112 * t9 + 3.38 * t9.powi(2))
},
"d(d,n)³He" => {
3.95e8 * t9.powf(-2.0/3.0) * (-4.259 / t9.powf(1.0/3.0)).exp()
* (1.0 + 0.0979 * t9)
},
"d(d,p)t" => {
4.17e8 * t9.powf(-2.0/3.0) * (-4.258 / t9.powf(1.0/3.0)).exp()
* (1.0 + 0.0978 * t9)
},
"t(d,n)⁴He" => {
1.63e11 * t9.powf(-2.0/3.0) * (-4.871 / t9.powf(1.0/3.0)).exp()
},
"³He(d,p)⁴He" => {
5.59e10 * t9.powf(-2.0/3.0) * (-7.183 / t9.powf(1.0/3.0)).exp()
* (1.0 + 0.0488 * t9)
},
"³He(n,p)t" => {
7.21e8 * (1.0 - 0.86 * t9 + 0.429 * t9.powi(2))
},
"⁴He(t,γ)⁷Li" => {
2.39e4 * t9.powf(-2.0/3.0) * (-8.09 / t9.powf(1.0/3.0)).exp()
},
_ => 1e-40, };
base_rate * scale
}
pub fn reverse_rate(&self, temp_k: f64) -> f64 {
if self.label == "p(n,γ)d" {
let forward_rate = self.rate_coefficient(temp_k);
let t_mev = K_B * temp_k * J_TO_EV * 1e-6;
forward_rate * (-self.q_value / t_mev).exp()
} else {
0.0
}
}
pub fn latex_equation(&self) -> String {
let reactants_str: Vec<_> = self.reactants.iter()
.map(|n| n.latex())
.collect();
let products_str: Vec<_> = self.products.iter()
.map(|n| n.latex())
.collect();
format!(
"${}\\rightarrow {}$",
reactants_str.join(" + "),
products_str.join(" + ")
)
}
}
pub fn standard_bbn_reactions() -> Vec<Reaction> {
vec![
Reaction::new(
vec![Nuclide::Proton, Nuclide::Neutron],
vec![Nuclide::Deuterium],
"p(n,γ)d"
),
Reaction::new(
vec![Nuclide::Deuterium, Nuclide::Proton],
vec![Nuclide::Helium3],
"d(p,γ)³He"
),
Reaction::new(
vec![Nuclide::Deuterium, Nuclide::Deuterium],
vec![Nuclide::Helium3, Nuclide::Neutron],
"d(d,n)³He"
),
Reaction::new(
vec![Nuclide::Deuterium, Nuclide::Deuterium],
vec![Nuclide::Tritium, Nuclide::Proton],
"d(d,p)t"
),
Reaction::new(
vec![Nuclide::Tritium, Nuclide::Deuterium],
vec![Nuclide::Helium4, Nuclide::Neutron],
"t(d,n)⁴He"
),
Reaction::new(
vec![Nuclide::Helium3, Nuclide::Deuterium],
vec![Nuclide::Helium4, Nuclide::Proton],
"³He(d,p)⁴He"
),
Reaction::new(
vec![Nuclide::Helium3, Nuclide::Neutron],
vec![Nuclide::Tritium, Nuclide::Proton],
"³He(n,p)t"
),
Reaction::new(
vec![Nuclide::Helium4, Nuclide::Tritium],
vec![Nuclide::Lithium7],
"⁴He(t,γ)⁷Li"
),
]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_binding_energies() {
assert!((Nuclide::Deuterium.binding_energy() - 2.224).abs() < 0.001);
assert!((Nuclide::Helium4.binding_energy() - 28.296).abs() < 0.001);
}
#[test]
fn test_reaction_rates() {
let reaction = Reaction::new(
vec![Nuclide::Proton, Nuclide::Neutron],
vec![Nuclide::Deuterium],
"p(n,γ)d"
);
let rate = reaction.rate_coefficient(1e9);
assert!(rate > 0.0);
}
}