Skip to main content

sciforge_lib/physics/nuclear/
fusion.rs

1use crate::constants::{C, EPSILON_0, G, K_B, MU_0, SIGMA_SB};
2
3pub fn pp_chain_rate(temperature_k: f64, density_kg_m3: f64, hydrogen_fraction: f64) -> f64 {
4    let t9 = temperature_k / 1e9;
5    if t9 <= 0.0 {
6        return 0.0;
7    }
8    let screening = 1.0 + 0.0123 * (density_kg_m3 / 1e5).powf(1.0 / 3.0) / t9;
9    let gamow = (-3.380 / t9.powf(1.0 / 3.0)).exp();
10    let s11 = 4.01e-22;
11    let rate = s11 * gamow * screening / t9.powf(2.0 / 3.0);
12    let energy_per_chain = 26.198 * 1.602_176_634e-13;
13    rate * density_kg_m3 * hydrogen_fraction.powi(2) * energy_per_chain
14}
15
16pub fn cno_cycle_rate(
17    temperature_k: f64,
18    density_kg_m3: f64,
19    hydrogen_fraction: f64,
20    cno_fraction: f64,
21) -> f64 {
22    let t9 = temperature_k / 1e9;
23    if t9 <= 0.0 {
24        return 0.0;
25    }
26    let gamow = (-15.228 / t9.powf(1.0 / 3.0)).exp();
27    let rate = 8.67e-17 * gamow / t9.powf(2.0 / 3.0);
28    let energy_per_cycle = 25.03 * 1.602_176_634e-13;
29    rate * density_kg_m3 * hydrogen_fraction * cno_fraction * energy_per_cycle
30}
31
32pub fn triple_alpha_rate(temperature_k: f64, density_kg_m3: f64, helium_fraction: f64) -> f64 {
33    let t9 = temperature_k / 1e9;
34    if t9 <= 0.0 {
35        return 0.0;
36    }
37    let rate = 7.831e-15 * (-4.4027 / t9).exp() / t9.powi(3);
38    let energy = 7.275 * 1.602_176_634e-13;
39    rate * density_kg_m3.powi(2) * helium_fraction.powi(3) * energy
40}
41
42pub fn nuclear_energy_generation(
43    temperature_k: f64,
44    density_kg_m3: f64,
45    hydrogen_fraction: f64,
46    helium_fraction: f64,
47    metal_fraction: f64,
48) -> f64 {
49    let pp = pp_chain_rate(temperature_k, density_kg_m3, hydrogen_fraction);
50    let cno = cno_cycle_rate(
51        temperature_k,
52        density_kg_m3,
53        hydrogen_fraction,
54        metal_fraction,
55    );
56    let ta = triple_alpha_rate(temperature_k, density_kg_m3, helium_fraction);
57    pp + cno + ta
58}
59
60pub fn thermal_pressure(electron_density: f64, temperature_k: f64) -> f64 {
61    2.0 * electron_density * K_B * temperature_k
62}
63
64pub fn magnetic_pressure(magnetic_field: f64) -> f64 {
65    magnetic_field.powi(2) / (2.0 * MU_0)
66}
67
68pub fn plasma_beta(electron_density: f64, temperature_k: f64, magnetic_field: f64) -> f64 {
69    thermal_pressure(electron_density, temperature_k) / magnetic_pressure(magnetic_field)
70}
71
72pub fn alfven_speed(magnetic_field: f64, density: f64) -> f64 {
73    magnetic_field / (MU_0 * density).sqrt()
74}
75
76pub fn plasma_frequency(electron_density: f64) -> f64 {
77    let e = 1.602_176_634e-19;
78    let m_e = 9.109_383_7e-31;
79    (electron_density * e * e / (EPSILON_0 * m_e)).sqrt()
80}
81
82pub fn debye_length(electron_density: f64, temperature_k: f64) -> f64 {
83    let e = 1.602_176_634e-19;
84    (EPSILON_0 * K_B * temperature_k / (electron_density * e * e)).sqrt()
85}
86
87pub fn radiative_loss_rate(electron_density: f64, temperature_k: f64) -> f64 {
88    let lambda = if temperature_k < 1e5 {
89        1e-26
90    } else if temperature_k < 1e7 {
91        1e-22 * (temperature_k / 1e6).powf(-0.7)
92    } else {
93        1e-23 * (temperature_k / 1e7).powf(0.5)
94    };
95    electron_density.powi(2) * lambda
96}
97
98pub fn thermal_conduction_flux(temperature_k: f64, length_scale: f64) -> f64 {
99    let kappa_0 = 9.2e-12;
100    kappa_0 * temperature_k.powf(3.5) / length_scale
101}
102
103pub fn sound_speed_plasma(temperature_k: f64, mean_particle_mass: f64) -> f64 {
104    let gamma = 5.0 / 3.0;
105    (gamma * K_B * temperature_k / mean_particle_mass).sqrt()
106}
107
108pub fn gyrofrequency(charge: f64, magnetic_field: f64, mass: f64) -> f64 {
109    charge.abs() * magnetic_field / mass
110}
111
112pub fn larmor_radius(mass: f64, velocity_perp: f64, charge: f64, magnetic_field: f64) -> f64 {
113    mass * velocity_perp / (charge.abs() * magnetic_field)
114}
115
116pub fn reconnection_rate_sweet_parker(alfven_speed_val: f64, lundquist_number: f64) -> f64 {
117    alfven_speed_val / lundquist_number.sqrt()
118}
119
120pub fn lundquist_number(
121    alfven_speed_val: f64,
122    length_scale: f64,
123    magnetic_diffusivity: f64,
124) -> f64 {
125    alfven_speed_val * length_scale / magnetic_diffusivity
126}
127
128pub fn coronal_loop_temperature(loop_length: f64, heating_rate: f64) -> f64 {
129    1400.0 * (heating_rate * loop_length.powi(2)).powf(1.0 / 3.0)
130}
131
132pub fn coronal_loop_density(heating_rate: f64, loop_length: f64, temperature_k: f64) -> f64 {
133    let kappa_0 = 9.2e-12;
134    heating_rate * loop_length / (2.0 * kappa_0 * temperature_k.powf(3.5) / loop_length) * 1e6
135}
136
137pub fn solar_flare_energy(magnetic_field: f64, volume: f64) -> f64 {
138    magnetic_pressure(magnetic_field) * volume
139}
140
141pub fn cme_kinetic_energy(mass: f64, velocity: f64) -> f64 {
142    0.5 * mass * velocity.powi(2)
143}
144
145pub fn sunspot_temperature(photosphere_temp: f64, suppression_factor: f64) -> f64 {
146    photosphere_temp * (1.0 - suppression_factor).powf(0.25)
147}
148
149pub fn differential_rotation_rate(equatorial_rate: f64, latitude: f64, a2: f64, a4: f64) -> f64 {
150    equatorial_rate - a2 * latitude.sin().powi(2) - a4 * latitude.sin().powi(4)
151}
152
153pub fn stellar_wind_mass_loss_si(luminosity: f64, escape_velocity: f64) -> f64 {
154    1e-14 * luminosity / (C * escape_velocity)
155}
156
157pub fn convective_envelope_depth(stellar_mass_solar: f64) -> f64 {
158    if stellar_mass_solar < 0.35 {
159        1.0
160    } else if stellar_mass_solar < 1.2 {
161        0.3 * (1.2 - stellar_mass_solar) / (1.2 - 0.35)
162    } else {
163        0.0
164    }
165}
166
167pub fn mixing_length_velocity(
168    convective_flux: f64,
169    density: f64,
170    temperature: f64,
171    pressure: f64,
172    mixing_length: f64,
173    g_local: f64,
174    cp: f64,
175) -> f64 {
176    let nabla_excess =
177        convective_flux / (density * cp * temperature * (pressure / (density * g_local)));
178    (g_local * mixing_length.powi(2) * nabla_excess / temperature).powf(1.0 / 3.0)
179}
180
181pub fn opacity_kramers(
182    density: f64,
183    temperature: f64,
184    hydrogen_fraction: f64,
185    metal_fraction: f64,
186) -> f64 {
187    let kappa_ff = 3.68e22
188        * (hydrogen_fraction + 0.2 * (1.0 + hydrogen_fraction))
189        * density
190        * temperature.powf(-3.5);
191    let kappa_bf =
192        4.34e25 * metal_fraction * (1.0 + hydrogen_fraction) * density * temperature.powf(-3.5);
193    kappa_ff + kappa_bf
194}
195
196pub fn radiative_temperature_gradient(
197    opacity: f64,
198    luminosity: f64,
199    mass_enclosed: f64,
200    pressure: f64,
201    temperature: f64,
202) -> f64 {
203    3.0 * opacity * luminosity * pressure
204        / (16.0 * std::f64::consts::PI * SIGMA_SB * C * G * mass_enclosed * temperature.powi(4))
205}