use scirs2_core::ndarray::Array1;
use scirs2_special::bessel::*;
use scirs2_special::{j0_zeros, j1_zeros};
use std::io::{self, Write};
fn generate_j0_zeros(num_zeros: usize) -> Result<Vec<f64>, String> {
let mut zeros = Vec::new();
for k in 1..=num_zeros {
match j0_zeros::<f64>(k) {
Ok(zero) => zeros.push(zero),
Err(e) => return Err(format!("Error computing J₀ zero {}: {}", k, e)),
}
}
Ok(zeros)
}
fn generate_j1_zeros(num_zeros: usize) -> Result<Vec<f64>, String> {
let mut zeros = Vec::new();
for k in 1..=num_zeros {
match j1_zeros::<f64>(k) {
Ok(zero) => zeros.push(zero),
Err(e) => return Err(format!("Error computing J₁ zero {}: {}", k, e)),
}
}
Ok(zeros)
}
#[allow(dead_code)]
fn main() {
println!("🚀 Welcome to the Interactive Bessel Functions Tutorial!");
println!("════════════════════════════════════════════════════════");
println!();
show_introduction();
loop {
show_menu();
match get_user_choice() {
1 => theory_overview(),
2 => explore_bessel_j(),
3 => explore_bessel_y(),
4 => explore_modified_bessel(),
5 => explore_spherical_bessel(),
6 => practical_applications(),
7 => interactive_plotting(),
8 => quiz_section(),
9 => {
println!("Thank you for using the Bessel Functions Tutorial! 🎓");
break;
}
_ => println!("Invalid choice. Please try again."),
}
println!();
pause();
}
}
#[allow(dead_code)]
fn show_introduction() {
println!("📚 BESSEL FUNCTIONS: Mathematical Foundations");
println!("─────────────────────────────────────────────");
println!();
println!("Bessel functions are solutions to Bessel's differential equation:");
println!("x²(d²y/dx²) + x(dy/dx) + (x² - ν²)y = 0");
println!();
println!("They appear in many physical problems with cylindrical symmetry:");
println!("• Heat conduction in cylinders");
println!("• Vibrations of circular membranes");
println!("• Electromagnetic waves in cylindrical waveguides");
println!("• Quantum mechanics (radial part of wave functions)");
println!();
println!("There are several types of Bessel functions:");
println!("• Jₙ(x): Bessel functions of the first kind");
println!("• Yₙ(x): Bessel functions of the second kind (Neumann functions)");
println!("• Iₙ(x): Modified Bessel functions of the first kind");
println!("• Kₙ(x): Modified Bessel functions of the second kind");
println!("• jₙ(x): Spherical Bessel functions of the first kind");
println!("• yₙ(x): Spherical Bessel functions of the second kind");
println!();
}
#[allow(dead_code)]
fn show_menu() {
println!("🎯 Choose a topic to explore:");
println!("1. 📖 Mathematical Theory Overview");
println!("2. 🟢 Bessel Functions of First Kind (Jₙ)");
println!("3. 🔴 Bessel Functions of Second Kind (Yₙ)");
println!("4. 🟡 Modified Bessel Functions (Iₙ, Kₙ)");
println!("5. 🔵 Spherical Bessel Functions");
println!("6. 🔧 Practical Applications");
println!("7. 📊 Interactive Plotting");
println!("8. 🧠 Knowledge Quiz");
println!("9. 🚪 Exit");
print!("\nEnter your choice (1-9): ");
io::stdout().flush().expect("Operation failed");
}
#[allow(dead_code)]
fn get_user_choice() -> i32 {
let mut input = String::new();
io::stdin()
.read_line(&mut input)
.expect("Failed to read input");
input.trim().parse().unwrap_or(0)
}
#[allow(dead_code)]
fn theory_overview() {
println!("\n📖 MATHEMATICAL THEORY OF BESSEL FUNCTIONS");
println!("══════════════════════════════════════════════");
println!("\n🔬 Historical Context:");
println!("Bessel functions were first studied by Daniel Bernoulli (1738) and");
println!("later systematically developed by Friedrich Bessel (1824) while");
println!("studying planetary motion.");
println!("\n📐 The Bessel Differential Equation:");
println!("x²(d²y/dx²) + x(dy/dx) + (x² - ν²)y = 0");
println!();
println!("where ν is called the 'order' of the Bessel function.");
println!("\n🌊 Series Representations:");
println!("Jₙ(x) = (x/2)ⁿ ∑[k=0 to ∞] [(-1)ᵏ/(k!(n+k)!)] * (x/2)²ᵏ");
println!("\n🎯 Key Properties:");
println!("• Jₙ(0) = δₙ₀ (Kronecker delta: 1 if n=0, 0 otherwise)");
println!("• J₋ₙ(x) = (-1)ⁿJₙ(x) for integer n");
println!("• Yₙ(x) → -∞ as x → 0⁺ for n ≥ 0");
println!("• For large x: Jₙ(x) ≈ √(2/πx) cos(x - nπ/2 - π/4)");
println!("\n🔢 Let's verify some properties with actual calculations:");
let j0_at_zero = j0(0.0);
println!("J₀(0) = {:.10} (should be 1.0)", j0_at_zero);
let j1_at_zero = j1(0.0);
println!("J₁(0) = {:.10} (should be 0.0)", j1_at_zero);
let x_large = 20.0;
let j0_large = j0(x_large);
let asymptotic = (2.0 / (std::f64::consts::PI * x_large)).sqrt()
* (x_large - std::f64::consts::PI / 4.0).cos();
println!("\nFor large x = {}:", x_large);
println!("J₀({}) = {:.6}", x_large, j0_large);
println!("Asymptotic approximation = {:.6}", asymptotic);
println!(
"Relative error = {:.2}%",
((j0_large - asymptotic) / j0_large * 100.0).abs()
);
}
#[allow(dead_code)]
fn explore_bessel_j() {
println!("\n🟢 BESSEL FUNCTIONS OF THE FIRST KIND (Jₙ)");
println!("═══════════════════════════════════════════════");
println!("\nBessel functions Jₙ(x) are the solutions that are finite at x = 0.");
println!("They oscillate with decreasing amplitude as x increases.");
loop {
println!("\nChoose an exploration:");
println!("1. Calculate Jₙ(x) for specific values");
println!("2. Find zeros of Bessel functions");
println!("3. Explore recurrence relations");
println!("4. Compare different orders");
println!("5. Return to main menu");
print!("Choice: ");
io::stdout().flush().expect("Operation failed");
match get_user_choice() {
1 => calculate_bessel_j_values(),
2 => explore_bessel_zeros(),
3 => explore_recurrence_relations(),
4 => compare_bessel_orders(),
5 => break,
_ => println!("Invalid choice."),
}
}
}
#[allow(dead_code)]
fn calculate_bessel_j_values() {
println!("\n🧮 Calculate Jₙ(x) for specific values");
println!("────────────────────────────────────────");
print!("Enter the order n (0, 1, 2, ...): ");
io::stdout().flush().expect("Operation failed");
let n: usize = get_user_input().parse().unwrap_or(0);
print!("Enter the value x: ");
io::stdout().flush().expect("Operation failed");
let x: f64 = get_user_input().parse().unwrap_or(1.0);
let result = match n {
0 => j0(x),
1 => j1(x),
_ => jn(n as i32, x),
};
println!("\nResult: J{}({}) = {:.10}", n, x, result);
println!("\nFor comparison:");
println!("J₀({}) = {:.10}", x, j0(x));
println!("J₁({}) = {:.10}", x, j1(x));
if n != 0 && n != 1 {
println!("J₂({}) = {:.10}", x, jn(2, x));
}
if x < 1.0 {
println!("\n📝 Note: For small x, Jₙ(x) ≈ (x/2)ⁿ/n! for n > 0");
let approx = (x / 2.0).powi(n as i32) / factorial(n);
if n > 0 {
println!("Small-x approximation: {:.10}", approx);
println!(
"Relative error: {:.2}%",
((result - approx) / result * 100.0).abs()
);
}
}
}
#[allow(dead_code)]
fn explore_bessel_zeros() {
println!("\n🎯 Zeros of Bessel Functions");
println!("────────────────────────────");
println!("Bessel function zeros are important in physics and engineering.");
println!("They appear in vibration problems, heat conduction, etc.");
print!("Enter order n (0 or 1): ");
io::stdout().flush().expect("Operation failed");
let n: usize = get_user_input().parse().unwrap_or(0);
print!("How many zeros to display? ");
io::stdout().flush().expect("Operation failed");
let num_zeros: usize = get_user_input().parse().unwrap_or(5).min(10);
println!("\nFirst {} zeros of J{}(x):", num_zeros, n);
println!("Zero # | Value");
println!("────────|──────────");
let zeros = match n {
0 => match generate_j0_zeros(num_zeros) {
Ok(z) => z,
Err(e) => {
println!("Error computing J₀ zeros: {}", e);
return;
}
},
1 => match generate_j1_zeros(num_zeros) {
Ok(z) => z,
Err(e) => {
println!("Error computing J₁ zeros: {}", e);
return;
}
},
_ => {
println!("Only n=0 and n=1 supported for zero finding in this demo.");
return;
}
};
for (i, zero) in zeros.iter().enumerate() {
println!("{:6} | {:8.6}", i + 1, zero);
let function_value: f64 = match n {
0 => j0(*zero),
1 => j1(*zero),
_ => 0.0,
};
if function_value.abs() < 1e-10 {
print!(" ✓");
} else {
print!(" (f({:.6}) = {:.2e})", zero, function_value);
}
println!();
}
if n == 0 {
println!("\n🔧 Application: Vibrating Circular Membrane");
println!(
"The first zero α₁ ≈ {:.4} determines the fundamental frequency:",
zeros[0]
);
println!("f₁ = (α₁/2πa)√(T/σ) where a=radius, T=tension, σ=surface density");
}
}
#[allow(dead_code)]
fn explore_recurrence_relations() {
println!("\n🔄 Recurrence Relations");
println!("──────────────────────");
println!("Bessel functions satisfy several recurrence relations:");
println!("1. Jₙ₋₁(x) + Jₙ₊₁(x) = (2n/x)Jₙ(x)");
println!("2. Jₙ₋₁(x) - Jₙ₊₁(x) = 2J'ₙ(x)");
println!("3. (d/dx)[xⁿJₙ(x)] = xⁿJₙ₋₁(x)");
print!("Enter x value to test relations: ");
io::stdout().flush().expect("Operation failed");
let x: f64 = get_user_input().parse().unwrap_or(5.0);
if x == 0.0 {
println!("Cannot test at x = 0 due to division by zero.");
return;
}
let j0_val = j0(x);
let j1_val = j1(x);
let j2_val = jn(2, x);
let lhs = j0_val + j2_val;
let rhs = (2.0 / x) * j1_val;
println!("\nTesting: J₀(x) + J₂(x) = (2/x)J₁(x) at x = {}", x);
println!("Left side: J₀({}) + J₂({}) = {:.8}", x, x, lhs);
println!("Right side: (2/{})J₁({}) = {:.8}", x, x, rhs);
println!("Difference: {:.2e}", (lhs - rhs).abs());
if (lhs - rhs).abs() < 1e-12 {
println!("✓ Recurrence relation verified!");
} else {
println!("⚠ Small numerical difference (expected for finite precision)");
}
}
#[allow(dead_code)]
fn compare_bessel_orders() {
println!("\n📊 Comparing Different Orders");
println!("─────────────────────────────");
print!("Enter x value: ");
io::stdout().flush().expect("Operation failed");
let x: f64 = get_user_input().parse().unwrap_or(3.0);
println!("\nBessel functions of different orders at x = {}:", x);
println!("Order n | Jₙ({}) | Behavior", x);
println!("────────|────────────|──────────");
for n in 0..=5 {
let val = match n {
0 => j0(x),
1 => j1(x),
_ => jn(n, x),
};
let behavior = if n == 0 {
"Starts at 1, first to oscillate"
} else if n == 1 {
"Starts at 0, derivative of J₀"
} else {
"Higher order, smaller amplitude"
};
println!("{:7} | {:10.6} | {}", n, val, behavior);
}
println!("\n📈 Observations:");
println!("• Higher-order Bessel functions have smaller amplitudes");
println!("• All orders oscillate with roughly the same period for large x");
println!("• J₀ starts at 1, while Jₙ (n>0) start at 0");
}
#[allow(dead_code)]
fn explore_bessel_y() {
println!("\n🔴 BESSEL FUNCTIONS OF THE SECOND KIND (Yₙ)");
println!("═══════════════════════════════════════════════");
println!("Bessel functions Yₙ(x) are the other linearly independent solutions");
println!("to Bessel's differential equation. They have a singularity at x = 0.");
print!("Enter x value (must be > 0): ");
io::stdout().flush().expect("Operation failed");
let x: f64 = get_user_input().parse().unwrap_or(1.0);
if x <= 0.0 {
println!("Error: Yₙ(x) is not defined for x ≤ 0");
return;
}
println!("\nValues at x = {}:", x);
println!("Y₀({}) = {:.6}", x, y0(x));
println!("Y₁({}) = {:.6}", x, y1(x));
println!("Y₂({}) = {:.6}", x, yn(2, x));
if x < 1.0 {
println!("\n📝 For small x:");
println!("Y₀(x) ≈ (2/π)[ln(x/2) + γ] where γ is Euler's constant");
println!("Y₁(x) ≈ -(2/πx)");
let euler_gamma = 0.5772156649015329;
let y0_approx = (2.0 / std::f64::consts::PI) * ((x / 2.0).ln() + euler_gamma);
let y1_approx = -2.0 / (std::f64::consts::PI * x);
println!("Y₀ approximation: {:.6}", y0_approx);
println!("Y₁ approximation: {:.6}", y1_approx);
}
}
#[allow(dead_code)]
fn explore_modified_bessel() {
println!("\n🟡 MODIFIED BESSEL FUNCTIONS (Iₙ, Kₙ)");
println!("═══════════════════════════════════════");
println!("Modified Bessel functions are solutions to the modified equation:");
println!("x²(d²y/dx²) + x(dy/dx) - (x² + ν²)y = 0");
println!("They are related to regular Bessel functions by:");
println!("Iₙ(x) = i⁻ⁿJₙ(ix) and Kₙ(x) = (π/2)i^(n+1)[Jₙ(ix) + iYₙ(ix)]");
print!("Enter x value: ");
io::stdout().flush().expect("Operation failed");
let x: f64 = get_user_input().parse().unwrap_or(1.0);
println!("\nModified Bessel functions at x = {}:", x);
println!("I₀({}) = {:.6} (exponentially growing)", x, i0(x));
println!("I₁({}) = {:.6} (exponentially growing)", x, i1(x));
println!("K₀({}) = {:.6} (exponentially decaying)", x, k0(x));
println!("K₁({}) = {:.6} (exponentially decaying)", x, k1(x));
println!("\n🔧 Applications:");
println!("• Heat conduction in cylindrical coordinates");
println!("• Modified Helmholtz equation");
println!("• Mathematical physics (especially diffusion)");
}
#[allow(dead_code)]
fn explore_spherical_bessel() {
println!("\n🔵 SPHERICAL BESSEL FUNCTIONS");
println!("═════════════════════════════");
println!("Spherical Bessel functions appear in problems with spherical symmetry.");
println!("They are related to regular Bessel functions by:");
println!("jₙ(x) = √(π/2x) J_{{n+1/2}}(x)");
println!("yₙ(x) = √(π/2x) Y_{{n+1/2}}(x)");
print!("Enter x value: ");
io::stdout().flush().expect("Operation failed");
let x: f64 = get_user_input().parse().unwrap_or(1.0);
print!("Enter maximum order n: ");
io::stdout().flush().expect("Operation failed");
let max_n: i32 = get_user_input().parse().unwrap_or(3).min(5);
println!("\nSpherical Bessel functions at x = {}:", x);
println!("Order | jₙ(x) | yₙ(x) | Elementary form");
println!("------|------------|------------|----------------");
for n in 0..=max_n {
let jn_val = spherical_jn(n, x);
let yn_val = spherical_yn(n, x);
let elementary = match n {
0 => "sin(x)/x, -cos(x)/x".to_string(),
1 => "sin(x)/x² - cos(x)/x, -cos(x)/x² - sin(x)/x".to_string(),
_ => "Complex expression".to_string(),
};
println!(
"{:5} | {:10.6} | {:10.6} | {}",
n, jn_val, yn_val, elementary
);
}
if x != 0.0 {
println!("\n✓ Verification of elementary forms:");
let j0_elementary = x.sin() / x;
let y0_elementary = -x.cos() / x;
println!(
"j₀({}) = {:.6}, sin(x)/x = {:.6}",
x,
spherical_jn(0, x),
j0_elementary
);
println!(
"y₀({}) = {:.6}, -cos(x)/x = {:.6}",
x,
spherical_yn(0, x),
y0_elementary
);
}
}
#[allow(dead_code)]
fn practical_applications() {
println!("\n🔧 PRACTICAL APPLICATIONS OF BESSEL FUNCTIONS");
println!("══════════════════════════════════════════════");
println!("Choose an application to explore:");
println!("1. 🥁 Vibrating Circular Membrane (Drum)");
println!("2. 🌡️ Heat Conduction in a Cylinder");
println!("3. 📡 Electromagnetic Waves in Circular Waveguide");
println!("4. ⚛️ Quantum Mechanics: Particle in a Box (cylindrical)");
println!("5. Return to main menu");
print!("Choice: ");
io::stdout().flush().expect("Operation failed");
match get_user_choice() {
1 => drum_vibration_demo(),
2 => heat_conduction_demo(),
3 => waveguide_demo(),
4 => quantum_mechanics_demo(),
5 => (),
_ => println!("Invalid choice."),
}
}
#[allow(dead_code)]
fn drum_vibration_demo() {
println!("\n🥁 VIBRATING CIRCULAR MEMBRANE (DRUM)");
println!("════════════════════════════════════");
println!("A circular drum head vibrates in modes characterized by Bessel functions.");
println!("The displacement u(r,θ,t) = J_m(k_mn*r) * [A*cos(mθ) + B*sin(mθ)] * cos(ω_mn*t)");
println!("where k_mn is the nth zero of J_m divided by the drum radius.");
print!("Enter drum radius (cm): ");
io::stdout().flush().expect("Operation failed");
let radius: f64 = get_user_input().parse().unwrap_or(10.0);
print!("Enter tension (N/m): ");
io::stdout().flush().expect("Operation failed");
let tension: f64 = get_user_input().parse().unwrap_or(1000.0);
print!("Enter surface density (kg/m²): ");
io::stdout().flush().expect("Operation failed");
let density: f64 = get_user_input().parse().unwrap_or(0.01);
println!("\nVibrational modes for circular drum:");
println!("Mode (m,n) | Frequency (Hz) | Description");
println!("-----------|----------------|------------");
let zeros_j0 = match generate_j0_zeros(3) {
Ok(z) => z,
Err(e) => {
println!("Error computing J₀ zeros: {}", e);
return;
}
};
let zeros_j1 = match generate_j1_zeros(3) {
Ok(z) => z,
Err(e) => {
println!("Error computing J₁ zeros: {}", e);
return;
}
};
for (n, &zero) in zeros_j0.iter().enumerate() {
let k = zero / (radius / 100.0); let frequency = k * (tension / density).sqrt() / (2.0 * std::f64::consts::PI);
println!(
" (0,{}) | {:8.1} | Symmetric mode",
n + 1,
frequency
);
}
for (n, &zero) in zeros_j1.iter().enumerate() {
let k = zero / (radius / 100.0);
let frequency = k * (tension / density).sqrt() / (2.0 * std::f64::consts::PI);
println!(
" (1,{}) | {:8.1} | One nodal diameter",
n + 1,
frequency
);
}
println!(
"\n📝 The fundamental mode (0,1) has frequency {:.1} Hz",
zeros_j0[0] / (radius / 100.0) * (tension / density).sqrt() / (2.0 * std::f64::consts::PI)
);
}
#[allow(dead_code)]
fn heat_conduction_demo() {
println!("\n🌡️ HEAT CONDUCTION IN A CYLINDER");
println!("═══════════════════════════════════");
println!("Temperature distribution in a cylinder with initial temperature T₀:");
println!("T(r,t) = T₀ * ∑[n=1 to ∞] A_n * J₀(α_n*r/R) * exp(-α_n²*κ*t/R²)");
println!("where α_n are zeros of J₀ and κ is thermal diffusivity.");
print!("Enter cylinder radius R (cm): ");
io::stdout().flush().expect("Operation failed");
let radius: f64 = get_user_input().parse().unwrap_or(5.0);
print!("Enter thermal diffusivity κ (cm²/s): ");
io::stdout().flush().expect("Operation failed");
let kappa: f64 = get_user_input().parse().unwrap_or(0.1);
print!("Enter time t (seconds): ");
io::stdout().flush().expect("Operation failed");
let time: f64 = get_user_input().parse().unwrap_or(10.0);
let zeros = match generate_j0_zeros(5) {
Ok(z) => z,
Err(e) => {
println!("Error computing J₀ zeros: {}", e);
return;
}
};
println!("\nTemperature decay at center (r=0) vs time:");
println!("(Relative to initial temperature T₀)");
println!("Time (s) | T(0,t)/T₀");
println!("---------|----------");
for t in [0.0, 5.0, 10.0, 20.0, 50.0, 100.0] {
if t > time + 100.0 {
break;
}
let mut temp_ratio = 0.0;
for &zero in zeros.iter() {
let coeff = 2.0 / (zero * j1(zero));
let exponential = (-zero.powi(2) * kappa * t / radius.powi(2)).exp();
temp_ratio += coeff * exponential;
}
println!("{:8.0} | {:8.4}", t, temp_ratio);
}
}
#[allow(dead_code)]
fn waveguide_demo() {
println!("\n📡 ELECTROMAGNETIC WAVES IN CIRCULAR WAVEGUIDE");
println!("══════════════════════════════════════════════");
println!("In a circular waveguide, electromagnetic modes are characterized by");
println!("Bessel functions. The cutoff frequency depends on Bessel function zeros.");
print!("Enter waveguide radius (cm): ");
io::stdout().flush().expect("Operation failed");
let radius: f64 = get_user_input().parse().unwrap_or(1.0);
let c = 2.998e10;
println!("\nLowest cutoff frequencies:");
println!("Mode | Cutoff Freq (GHz) | Field Pattern");
println!("--------|-------------------|---------------");
let zeros_j0 = match generate_j0_zeros(2) {
Ok(z) => z,
Err(e) => {
println!("Error computing J₀ zeros: {}", e);
return;
}
};
let zeros_j1 = match generate_j1_zeros(3) {
Ok(z) => z,
Err(e) => {
println!("Error computing J₁ zeros: {}", e);
return;
}
};
let fc_te01 = zeros_j1[0] * c / (2.0 * std::f64::consts::PI * radius) / 1e9;
println!("TE₀₁ | {:8.2} | No angular variation", fc_te01);
let fc_tm01 = zeros_j0[0] * c / (2.0 * std::f64::consts::PI * radius) / 1e9;
println!("TM₀₁ | {:8.2} | Longitudinal field", fc_tm01);
let fc_te11 = zeros_j1[1] * c / (2.0 * std::f64::consts::PI * radius) / 1e9;
println!(
"TE₁₁ | {:8.2} | One angular variation",
fc_te11
);
println!(
"\n📝 The TE₀₁ mode has the lowest cutoff frequency: {:.2} GHz",
fc_te01
);
}
#[allow(dead_code)]
fn quantum_mechanics_demo() {
println!("\n⚛️ QUANTUM MECHANICS: PARTICLE IN CYLINDRICAL BOX");
println!("═══════════════════════════════════════════════");
println!("For a particle in a cylindrical box, the radial part of the");
println!("wavefunction involves Bessel functions:");
println!("ψ(r,φ,z) = A * J_m(k_r*r) * e^(imφ) * sin(nπz/L)");
print!("Enter cylinder radius (Angstroms): ");
io::stdout().flush().expect("Operation failed");
let radius: f64 = get_user_input().parse().unwrap_or(10.0);
print!("Enter cylinder height (Angstroms): ");
io::stdout().flush().expect("Operation failed");
let height: f64 = get_user_input().parse().unwrap_or(20.0);
let hbar: f64 = 1.0; let mass: f64 = 1.0; let bohr = 0.529;
println!("\nLowest energy levels (in Hartree):");
println!("State (m,k,n) | Energy | Description");
println!("--------------|--------|------------");
let zeros_j0 = match generate_j0_zeros(3) {
Ok(z) => z,
Err(e) => {
println!("Error computing J₀ zeros: {}", e);
return;
}
};
let zeros_j1 = match generate_j1_zeros(2) {
Ok(z) => z,
Err(e) => {
println!("Error computing J₁ zeros: {}", e);
return;
}
};
let mut energies = Vec::new();
for n_z in 1..=3 {
for (k_idx, &zero) in zeros_j0.iter().enumerate() {
let k_r: f64 = zero * bohr / radius;
let k_z = n_z as f64 * std::f64::consts::PI * bohr / height;
let energy = hbar.powi(2) / (2.0 * mass) * (k_r.powi(2) + k_z.powi(2));
energies.push((
format!("(0,{},{})", k_idx + 1, n_z),
energy,
"Symmetric radial",
));
}
for (k_idx, &zero) in zeros_j1.iter().enumerate() {
let k_r: f64 = zero * bohr / radius;
let k_z = n_z as f64 * std::f64::consts::PI * bohr / height;
let energy = hbar.powi(2) / (2.0 * mass) * (k_r.powi(2) + k_z.powi(2));
energies.push((
format!("(1,{},{})", k_idx + 1, n_z),
energy,
"Angular variation",
));
}
}
energies.sort_by(|a, b| a.1.partial_cmp(&b.1).expect("Operation failed"));
for (i, (state, energy, desc)) in energies.iter().take(8).enumerate() {
println!("{:13} | {:6.4} | {}", state, energy, desc);
if i == 0 {
println!(" | | <- Ground state");
}
}
}
#[allow(dead_code)]
fn interactive_plotting() {
println!("\n📊 INTERACTIVE PLOTTING");
println!("═══════════════════════");
println!("Choose what to plot:");
println!("1. Bessel functions J₀, J₁, J₂");
println!("2. Modified Bessel functions I₀, K₀");
println!("3. Spherical Bessel functions j₀, j₁, j₂");
println!("4. Custom function comparison");
print!("Choice: ");
io::stdout().flush().expect("Operation failed");
match get_user_choice() {
1 => plot_regular_bessel(),
2 => plot_modified_bessel(),
3 => plot_spherical_bessel(),
4 => plot_custom_comparison(),
_ => println!("Invalid choice."),
}
}
#[allow(dead_code)]
fn plot_regular_bessel() {
println!("\n📈 Plotting Regular Bessel Functions");
println!("─────────────────────────────────────");
let xmax = 15.0;
let n_points = 150;
let x_values: Vec<f64> = Array1::linspace(0.01, xmax, n_points).to_vec();
println!(
"\nBessel Functions J₀(x), J₁(x), J₂(x) for x ∈ [0, {}]",
xmax
);
println!("(Approximate ASCII plot)");
println!();
let plot_height = 15;
let plot_width = 80;
let j0_values: Vec<f64> = x_values.iter().map(|&x| j0(x)).collect();
let j1_values: Vec<f64> = x_values.iter().map(|&x| j1(x)).collect();
let j2_values: Vec<f64> = x_values.iter().map(|&x| jn(2, x)).collect();
let ymin = -0.5;
let ymax = 1.0;
for row in 0..plot_height {
let y = ymax - (row as f64 / (plot_height - 1) as f64) * (ymax - ymin);
if row == 0 || row == plot_height - 1 {
print!("{:5.2} ", y);
} else if (y - 0.0).abs() < 0.05 {
print!(" 0.00 ");
} else {
print!(" ");
}
for col in 0..plot_width {
let x_idx = (col as f64 / plot_width as f64 * (n_points - 1) as f64) as usize;
if x_idx < j0_values.len() {
let j0_diff = (j0_values[x_idx] - y).abs();
let j1_diff = (j1_values[x_idx] - y).abs();
let j2_diff = (j2_values[x_idx] - y).abs();
if j0_diff < 0.05 {
print!("0");
} else if j1_diff < 0.05 {
print!("1");
} else if j2_diff < 0.05 {
print!("2");
} else if (y - 0.0).abs() < 0.02 {
print!("-");
} else {
print!(" ");
}
} else {
print!(" ");
}
}
println!();
}
println!(
" 0 {} {} {} {}",
xmax / 4.0,
xmax / 2.0,
3.0 * xmax / 4.0,
xmax
);
println!();
println!("Legend: 0 = J₀(x), 1 = J₁(x), 2 = J₂(x)");
println!("\nKey values:");
for x in [1.0, 5.0, 10.0] {
println!(
"x = {}: J₀ = {:6.3}, J₁ = {:6.3}, J₂ = {:6.3}",
x,
j0(x),
j1(x),
jn(2, x)
);
}
}
#[allow(dead_code)]
fn plot_modified_bessel() {
println!("\n📈 Plotting Modified Bessel Functions");
println!("──────────────────────────────────────");
let xmax = 3.0; let n_points = 60;
let _x_values: Vec<f64> = Array1::linspace(0.01, xmax, n_points).to_vec();
println!(
"\nModified Bessel Functions I₀(x) and K₀(x) for x ∈ [0, {}]",
xmax
);
println!("Note: I₀ grows exponentially, K₀ decays exponentially");
println!("\nValues at selected points:");
println!("x | I₀(x) | K₀(x) | Behavior");
println!("------|----------|----------|----------");
for &x in [0.1, 0.5, 1.0, 2.0, 3.0].iter() {
if x <= xmax {
let i0_val = i0(x);
let k0_val = k0(x);
let behavior = if x < 0.5 {
"I₀≈1, K₀≈-ln(x)"
} else if x < 2.0 {
"Transition region"
} else {
"I₀ grows, K₀ decays"
};
println!("{:5.1} | {:8.4} | {:8.4} | {}", x, i0_val, k0_val, behavior);
}
}
println!("\n📝 Asymptotic behavior:");
println!("For large x: I₀(x) ≈ e^x/√(2πx), K₀(x) ≈ √(π/2x) e^(-x)");
}
#[allow(dead_code)]
fn plot_spherical_bessel() {
println!("\n📈 Plotting Spherical Bessel Functions");
println!("───────────────────────────────────────");
let xmax = 15.0;
println!(
"\nSpherical Bessel Functions j₀(x), j₁(x), j₂(x) for x ∈ [0, {}]",
xmax
);
println!("\nElementary function forms:");
println!("j₀(x) = sin(x)/x");
println!("j₁(x) = sin(x)/x² - cos(x)/x");
println!("j₂(x) = (3/x³ - 1/x)sin(x) - (3/x²)cos(x)");
println!("\nValues at selected points:");
println!("x | j₀(x) | j₁(x) | j₂(x) | sin(x)/x");
println!("------|----------|----------|----------|----------");
for &x in [
1.0f64,
std::f64::consts::PI,
std::f64::consts::TAU,
3.0 * std::f64::consts::PI,
4.0 * std::f64::consts::PI,
]
.iter()
{
if x <= xmax {
let j0_val = spherical_jn(0, x);
let j1_val = spherical_jn(1, x);
let j2_val = spherical_jn(2, x);
let sinc_val = x.sin() / x;
println!(
"{:5.2} | {:8.4} | {:8.4} | {:8.4} | {:8.4}",
x, j0_val, j1_val, j2_val, sinc_val
);
}
}
}
#[allow(dead_code)]
fn plot_custom_comparison() {
println!("\n📊 Custom Function Comparison");
println!("─────────────────────────────");
println!("Choose comparison:");
println!("1. Regular vs Modified Bessel (same order)");
println!("2. Bessel vs Spherical Bessel");
println!("3. Different orders of same type");
print!("Choice: ");
io::stdout().flush().expect("Operation failed");
match get_user_choice() {
1 => {
println!("\nComparing J₀(x) vs I₀(x):");
for &x in [0.5, 1.0, 2.0, 3.0].iter() {
println!(
"x = {}: J₀ = {:7.4}, I₀ = {:7.4} (ratio I₀/J₀ = {:6.2})",
x,
j0(x),
i0(x),
i0(x) / j0(x)
);
}
}
2 => {
println!("\nComparing J₀(x) vs j₀(x) = sin(x)/x:");
for &x in [1.0, 5.0, 10.0].iter() {
let j0_reg = j0(x);
let j0_sph = spherical_jn(0, x);
println!(
"x = {}: J₀ = {:7.4}, j₀ = {:7.4} (ratio = {:6.3})",
x,
j0_reg,
j0_sph,
j0_sph / j0_reg
);
}
}
3 => {
println!("\nComparing different orders at x = 5.0:");
let x = 5.0;
for n in 0..=4 {
let val = match n {
0 => j0(x),
1 => j1(x),
_ => jn(n, x),
};
println!("J{}({}) = {:8.5}", n, x, val);
}
}
_ => println!("Invalid choice."),
}
}
#[allow(dead_code)]
fn quiz_section() {
println!("\n🧠 BESSEL FUNCTIONS KNOWLEDGE QUIZ");
println!("═════════════════════════════════════");
let mut score = 0;
let total_questions = 5;
println!("\nQuestion 1: What is J₀(0)?");
println!("a) 0");
println!("b) 1");
println!("c) ∞");
println!("d) undefined");
print!("Your answer: ");
io::stdout().flush().expect("Operation failed");
let answer1 = get_user_input().trim().to_lowercase();
if answer1 == "b" {
println!("✓ Correct! J₀(0) = 1");
score += 1;
} else {
println!("✗ Incorrect. J₀(0) = 1 because J₀ is the only Bessel function finite at origin with this value.");
}
println!("\nQuestion 2: What happens to Yₙ(x) as x → 0⁺?");
println!("a) Approaches 0");
println!("b) Approaches 1");
println!("c) Approaches -∞");
println!("d) Oscillates");
print!("Your answer: ");
io::stdout().flush().expect("Operation failed");
let answer2 = get_user_input().trim().to_lowercase();
if answer2 == "c" {
println!("✓ Correct! Yₙ(x) has a logarithmic singularity at x = 0");
score += 1;
} else {
println!("✗ Incorrect. Yₙ(x) → -∞ as x → 0⁺ due to logarithmic singularity.");
}
println!("\nQuestion 3: Modified Bessel functions Iₙ(x) are solutions to which equation?");
println!("a) x²y'' + xy' + (x² - ν²)y = 0");
println!("b) x²y'' + xy' - (x² + ν²)y = 0");
println!("c) x²y'' + xy' + x²y = 0");
println!("d) xy'' + y' + xy = 0");
print!("Your answer: ");
io::stdout().flush().expect("Operation failed");
let answer3 = get_user_input().trim().to_lowercase();
if answer3 == "b" {
println!("✓ Correct! Note the minus sign before (x² + ν²)");
score += 1;
} else {
println!(
"✗ Incorrect. Modified Bessel equation has minus sign: x²y'' + xy' - (x² + ν²)y = 0"
);
}
println!("\nQuestion 4: The relationship j₀(x) = ? (spherical Bessel)");
println!("a) J₀(x)");
println!("b) sin(x)/x");
println!("c) cos(x)/x");
println!("d) x*J₁(x)");
print!("Your answer: ");
io::stdout().flush().expect("Operation failed");
let answer4 = get_user_input().trim().to_lowercase();
if answer4 == "b" {
println!("✓ Correct! j₀(x) = sin(x)/x is the simplest spherical Bessel function");
score += 1;
} else {
println!("✗ Incorrect. j₀(x) = sin(x)/x, which makes it very simple to compute.");
}
println!("\nQuestion 5: In what physical problem do Bessel function zeros appear?");
println!("a) Heat conduction in rectangular plate");
println!("b) Vibrations of circular drum");
println!("c) Simple harmonic oscillator");
println!("d) Radioactive decay");
print!("Your answer: ");
io::stdout().flush().expect("Operation failed");
let answer5 = get_user_input().trim().to_lowercase();
if answer5 == "b" {
println!("✓ Correct! Zeros determine the vibrational frequencies of circular membranes");
score += 1;
} else {
println!("✗ Incorrect. Bessel zeros appear in circular drum vibrations, determining mode frequencies.");
}
println!("\n🏆 QUIZ RESULTS");
println!("═══════════════");
println!("Your score: {}/{}", score, total_questions);
match score {
5 => println!("🌟 Perfect! You're a Bessel function expert!"),
4 => println!("🎉 Excellent! You have strong understanding of Bessel functions."),
3 => println!("👍 Good job! You understand the basics well."),
2 => println!("📚 Not bad! Review the theory and try again."),
_ => println!("🤔 Consider reviewing the tutorial sections for better understanding."),
}
}
#[allow(dead_code)]
fn get_user_input() -> String {
let mut input = String::new();
io::stdin()
.read_line(&mut input)
.expect("Failed to read input");
input.trim().to_string()
}
#[allow(dead_code)]
fn pause() {
print!("\nPress Enter to continue...");
io::stdout().flush().expect("Operation failed");
let mut input = String::new();
io::stdin()
.read_line(&mut input)
.expect("Failed to read input");
}
#[allow(dead_code)]
fn factorial(n: usize) -> f64 {
(1..=n).map(|x| x as f64).product()
}