use crate::traits::{ChemElement,Isotope};
use crate::nstruct::core::Nuclide;
use crate::constant::*;
use crate::mmodel::mass_model;
use crate::decay::DecayMode;
use crate::nuclidedata::half_life::HALF_LIFE;
use crate::nuclidedata::decay_chain::DECAY_CHAIN;
use crate::Particle;
use crate::rng::rand;
use crate::decay::is_mode_recorded;
use crate::decay::dhelper::decay_mode_idx;
use crate::decay::dhelper::decay_select;
use crate::decay::decayimpl::decayindex;
impl Isotope for Nuclide {
fn mass_deficit(&self) -> f64 {
let (p,n) = self.proton_neutron();
( PROTONMASS* p as f64
+ ELECTRONMASS * p as f64
+ NEUTRONMASS * n as f64)
- self.am()
}
fn binding_energy(&self) -> f64 {
let (z, a) = (
self.proton_neutron().0,
self.proton_neutron().0 + self.proton_neutron().1,
);
mass_model(a, z)
}
fn branching_ratio<T: DecayMode>(&self) -> f64{
let idx = self.nuclide_index() * 6 + 5;
match decayindex::<T>(idx){
Some(x) => x as f64/FLOAT_64,
None => f64::NAN,
}
}
fn half_life<T: DecayMode>(&self) -> f64 {
let branch = self.branching_ratio::<T>();
HALF_LIFE[self.nuclide_index()]/branch
}
fn mean_lifetime<T: DecayMode>(&self) -> f64 {
self.half_life::<T>() * std::f64::consts::LOG2_E
}
fn decay_constant<T: DecayMode>(&self) -> f64 {
self.mean_lifetime::<T>().recip()
}
fn decay_probability<T: DecayMode>(&self, time: f64) -> f64{
1.0 - (-self.decay_constant::<T>() * time).exp()
}
fn daughter_theoretical<T: DecayMode>(&self) -> Option<Self>{
T::decay_result(self)
}
fn decay_time<T: DecayMode>(&self, time: f64) -> bool {
let prob =
((1.0 - (-self.decay_constant::<T>() * time).exp()) * FLOAT_64) as u64;
prob > rand()
}
fn decay_string(&self) -> String {
let mut unu_alea =
((DECAY_CHAIN[self.nuclide_index() * 6] as f64 / FLOAT_64) * 100.0)
.to_string();
unu_alea.truncate(4);
unu_alea.push_str("% ");
let mut doua_alea = ((DECAY_CHAIN[self.nuclide_index() * 6 + 1] as f64
/ FLOAT_64)
* 100.0)
.to_string();
doua_alea.truncate(4);
doua_alea.push_str("% ");
let mut trei_alea = ((DECAY_CHAIN[self.nuclide_index() * 6 + 2] as f64
/ FLOAT_64)
* 100.0)
.to_string();
trei_alea.truncate(4);
trei_alea.push_str("% ");
let mut patru_alea = ((DECAY_CHAIN[self.nuclide_index() * 6 + 3] as f64
/ FLOAT_64)
* 100.0)
.to_string();
patru_alea.truncate(4);
patru_alea.push_str("% ");
let mut cinci_alea = ((DECAY_CHAIN[self.nuclide_index() * 6 + 4] as f64
/ FLOAT_64)
* 100.0)
.to_string();
cinci_alea.truncate(4);
cinci_alea.push_str("% ");
let mut decay_str = vec![];
let decay_vector = DECAY_CHAIN[self.nuclide_index() * 6 + 5].to_be_bytes();
for i in decay_vector[..5].iter() {
match i {
1 => decay_str.push("α; "),
2 => decay_str.push("p; "),
3 => decay_str.push("2p; "),
4 => decay_str.push("n; "),
5 => decay_str.push("2n; "),
6 => decay_str.push("EC; "),
7 => decay_str.push("2EC; "),
8 => decay_str.push("β− + p; "),
9 => decay_str.push("β+; "),
10 => decay_str.push("2β+; "),
11 => decay_str.push("β−; "),
12 => decay_str.push("2β−; "),
13 => decay_str.push("β− + n; "),
14 => decay_str.push("β− + 2n; "),
15 => decay_str.push("β− + 3n; "),
16 => decay_str.push("β+ + p; "),
17 => decay_str.push("β+ + 2p; "),
18 => decay_str.push("β+ + 3p; "),
19 => decay_str.push("β− + α; "),
20 => decay_str.push("β+ + α; "),
21 => decay_str.push("β− + d; "),
22 => decay_str.push("β− + t; "),
23 => decay_str.push("SF; "),
24 => decay_str.push("β− + SF; "),
25 => decay_str.push("β+ + SF; "),
26 => decay_str.push("C-14; "),
27 => decay_str.push("Ne-20; "),
28 => decay_str.push("Ne-24; "),
29 => decay_str.push("Ne-20 + Ne-24; "),
30 => decay_str.push("Si-32; "),
31 => decay_str.push("Si-34; "),
_ => decay_str.push("Null"),
}
}
let mut decayvec = vec![];
decayvec.push(unu_alea);
decayvec.push(decay_str[0].to_string());
decayvec.push(doua_alea);
decayvec.push(decay_str[1].to_string());
decayvec.push(trei_alea);
decayvec.push(decay_str[2].to_string());
decayvec.push(patru_alea);
decayvec.push(decay_str[3].to_string());
decayvec.push(cinci_alea);
decayvec.push(decay_str[4].to_string());
if decayvec[0] == "0% " {
"Stable".to_string()
} else {
match decayvec.iter().position(|r| r == "Null") {
Some(x) => decayvec.truncate(x - 1),
None => decayvec.truncate(10),
}
decayvec.join("")
}
}
fn daughter_energetic<T: DecayMode>(&mut self) -> (f64,Vec<Particle>){
T::decay(self)
}
fn daughter<T: DecayMode>(&self) -> Option<Self>{
if is_mode_recorded::<T>(self){
return T::decay_result(self)
}
None
}
fn decay_q<T: DecayMode>(&self) -> f64{
T::q_value(self)
}
fn decay<T: DecayMode>(&mut self, mut time: f64) -> (f64, Vec<Particle>) {
let mut total_energy = 0f64;
let mut particlevec = vec![];
if T::decay_index() == 254u8{
loop {
let (b,b_idx) = decay_mode_idx(self);
let idx = self.nuclide_index() * 6usize + b_idx as usize;
let ratio = (DECAY_CHAIN[idx] as f64)/FLOAT_64;
let mean_time = (HALF_LIFE[self.nuclide_index()]/ratio) * std::f64::consts::LOG2_E;
if mean_time >= time || mean_time == f64::INFINITY{
return (total_energy,particlevec)
}
let (energy, p_vector) = decay_select(self,b);
particlevec.extend_from_slice(&p_vector[..]);
total_energy+=energy;
time-=mean_time;
}
}
loop{
if !is_mode_recorded::<T>(self){
return (total_energy,particlevec)
}
let mean_time = self.mean_lifetime::<T>();
if mean_time >= time || mean_time.is_infinite() || mean_time.is_nan(){
return (total_energy,particlevec)
}
let (energy, p_vector) = T::decay(self);
particlevec.extend_from_slice(&p_vector[..]);
total_energy+=energy;
time-=mean_time;
}
}
}