use spintronics::negf::{
GreenFunction, Hamiltonian1D, KeldyshSolver, LeadSelfEnergy, ShotNoise, TransportCalculator,
};
use spintronics::prelude::*;
fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
println!("=== NEGF Quantum Transport: Transmission and I-V Characteristics ===\n");
let n_sites = 20_usize;
let onsite_energy = 0.0_f64; let hopping = -1.0_f64;
println!("=== 1. Tight-Binding Chain ===");
let hamiltonian =
Hamiltonian1D::from_uniform(n_sites, onsite_energy, hopping).expect("valid Hamiltonian");
println!(" Sites : {}", hamiltonian.n_sites());
println!(" Hopping t = {:.2} eV", hamiltonian.hopping);
println!(
" Band : [{:.2}, {:.2}] eV (2|t| = {:.2} eV bandwidth)",
2.0 * hopping,
-2.0 * hopping,
4.0 * hopping.abs()
);
println!(" On-site energies (first 5 sites):");
for i in 0..5 {
let e = hamiltonian.site_energy(i).expect("valid site index");
println!(" site {:>2} : ε = {:.3} eV", i, e);
}
println!("\n=== 2. Transmission Spectrum T(E) ===");
let gamma = 0.5_f64; let eta = 1e-3_f64;
let sigma_l = LeadSelfEnergy::new(gamma, 0.0).expect("valid left lead");
let sigma_r = LeadSelfEnergy::new(gamma, 0.0).expect("valid right lead");
let gf = GreenFunction::new(hamiltonian.clone(), sigma_l.clone(), sigma_r.clone(), eta)
.expect("valid GreenFunction");
let tc =
TransportCalculator::new(gf.clone(), -3.0, 3.0, 200).expect("valid TransportCalculator");
println!(" Γ_L = Γ_R = {:.2} eV (wide-band lead coupling)", gamma);
println!(" η = {:.0e} eV (broadening)", eta);
println!();
println!(" {:>8} {:>14}", "E (eV)", "T(E)");
println!(" {}", "-".repeat(25));
for k in 0..=10 {
let energy = -2.5 + k as f64 * 0.5;
let t_e = tc.transmission(energy).expect("transmission evaluation");
println!(" {:>8.3} {:>14.6}", energy, t_e);
}
println!("\n=== 3. I-V Characteristics (T = 300 K, symmetric bias) ===");
let temperature = 300.0_f64;
let g0 = CONDUCTANCE_QUANTUM;
let ev_to_joule = E_CHARGE;
println!(" T = {:.0} K", temperature);
println!(" G₀ = {:.4e} S (conductance quantum e²/h)", g0);
println!(" μ_L = +V/2, μ_R = −V/2 (symmetric bias)\n");
println!(
" {:>8} {:>14} {:>18} {:>12}",
"V (eV)", "I (µA)", "dI/dV (G₀)", "G_0·T(0)"
);
println!(" {}", "-".repeat(58));
let g_zero_bias = tc
.zero_bias_conductance(temperature)
.expect("zero-bias conductance");
let g_zero_in_g0 = g_zero_bias / g0;
for k in 0..=10 {
let v_bias = k as f64 * 0.2; let current_raw = tc
.current(v_bias, temperature)
.expect("current calculation");
let current_a = current_raw * ev_to_joule;
let current_ua = current_a * 1.0e6; let di_dv_raw = tc
.differential_conductance(v_bias, temperature)
.expect("differential conductance");
let di_dv = di_dv_raw * ev_to_joule; let di_dv_g0 = di_dv / g0;
let g0t_str = if k == 0 {
format!("{:.6}", g_zero_in_g0)
} else {
String::from("")
};
println!(
" {:>8.1} {:>14.4} {:>18.6} {:>12}",
v_bias, current_ua, di_dv_g0, g0t_str
);
}
println!("\n=== 4. Shot Noise and Fano Factor ===");
let tc_noise = TransportCalculator::new(gf.clone(), -3.0, 3.0, 400)
.expect("valid TransportCalculator for noise");
let shot_noise = ShotNoise::new(tc_noise);
println!(" Poissonian limit : F = 1 (tunnel junction, T → 0)");
println!(" Ballistic limit : F = 0 (perfect channel, T = 1)");
println!(" Sub-Poissonian noise indicates coherent quantum transport\n");
println!(
" {:>8} {:>18} {:>14} {:>18} {:>10}",
"V (eV)", "S_shot (A²/Hz)", "I (µA)", "S_total (A²/Hz)", "Fano F"
);
println!(" {}", "-".repeat(74));
for &v_bias in &[0.5_f64, 1.0, 1.5] {
let s_shot = shot_noise
.shot_noise_only(v_bias, temperature)
.expect("shot noise");
let s_total = shot_noise
.noise_zero_freq(v_bias, temperature)
.expect("total noise");
let current_raw = shot_noise
.transport
.current(v_bias, temperature)
.expect("current for noise");
let current_ua = current_raw * ev_to_joule * 1.0e6;
let fano = shot_noise
.fano_factor(v_bias, temperature)
.expect("Fano factor");
println!(
" {:>8.2} {:>18.4e} {:>14.4} {:>18.4e} {:>10.4}",
v_bias, s_shot, current_ua, s_total, fano
);
}
let fano_mid = shot_noise
.fano_factor(1.0, temperature)
.expect("Fano at 1.0 V");
let regime = if fano_mid < 0.1 {
"near-ballistic"
} else if fano_mid < 0.5 {
"sub-Poissonian (coherent)"
} else {
"near-Poissonian (tunnel)"
};
println!(
"\n Transport regime at V=1.0 eV: F = {:.4} → {}",
fano_mid, regime
);
println!("\n=== 5. Anderson Disorder and Localization ===");
let disorder_sigma = 0.3_f64; let seed = 42_u64;
let h_disordered = Hamiltonian1D::from_uniform(n_sites, onsite_energy, hopping)
.expect("valid Hamiltonian")
.with_disorder(disorder_sigma, seed);
println!(" σ_disorder = {:.2} eV, seed = {}", disorder_sigma, seed);
println!(" Disordered on-site energies (first 5 sites):");
for i in 0..5 {
let e = h_disordered.site_energy(i).expect("valid site index");
println!(" site {:>2} : ε = {:+.4} eV", i, e);
}
let sigma_l_d = LeadSelfEnergy::new(gamma, 0.0).expect("valid left lead");
let sigma_r_d = LeadSelfEnergy::new(gamma, 0.0).expect("valid right lead");
let gf_disordered = GreenFunction::new(h_disordered.clone(), sigma_l_d, sigma_r_d, eta)
.expect("valid disordered GreenFunction");
let tc_disordered = TransportCalculator::new(gf_disordered.clone(), -3.0, 3.0, 200)
.expect("valid disordered TransportCalculator");
println!("\n T(E) comparison: uniform vs disordered chain\n");
println!(
" {:>8} {:>16} {:>16} {:>12}",
"E (eV)", "T_uniform", "T_disordered", "Ratio"
);
println!(" {}", "-".repeat(56));
for k in 0..=10 {
let energy = -2.5 + k as f64 * 0.5;
let t_uniform = tc.transmission(energy).expect("uniform transmission");
let t_disorder = tc_disordered
.transmission(energy)
.expect("disordered transmission");
let ratio = if t_uniform > 1e-12 {
t_disorder / t_uniform
} else {
0.0
};
println!(
" {:>8.3} {:>16.6} {:>16.6} {:>12.4}",
energy, t_uniform, t_disorder, ratio
);
}
let t_clean_ef = tc.transmission(0.0).expect("clean T(E_F)");
let t_dirty_ef = tc_disordered.transmission(0.0).expect("disordered T(E_F)");
let localization_factor = if t_clean_ef > 1e-12 {
t_dirty_ef / t_clean_ef
} else {
0.0
};
println!("\n At E = 0 (band centre):");
println!(" T_uniform = {:.6}", t_clean_ef);
println!(" T_disordered = {:.6}", t_dirty_ef);
println!(
" T_dis / T_uni = {:.4} (Anderson localization suppresses transmission)",
localization_factor
);
println!("\n=== 6. Keldysh Non-Equilibrium Carrier Density ===");
let v_nonequil = 0.5_f64; let mu_l_ne = v_nonequil / 2.0;
let mu_r_ne = -v_nonequil / 2.0;
let keldysh = KeldyshSolver::new(gf.clone());
let density = keldysh
.nonequilibrium_density(mu_l_ne, mu_r_ne, temperature, -3.0, 3.0, 200)
.expect("nonequilibrium density");
println!(
" V = {:.2} eV (μ_L = {:+.3}, μ_R = {:+.3})",
v_nonequil, mu_l_ne, mu_r_ne
);
println!(" T = {:.0} K", temperature);
println!(" Per-site carrier density n_i (integrated over band):\n");
println!(" {:>6} {:>20}", "Site", "n_i (per eV·site)");
println!(" {}", "-".repeat(30));
for (i, &ni) in density.iter().enumerate() {
println!(" {:>6} {:>20.6e}", i, ni);
}
let total: f64 = density.iter().sum();
println!(
" {:>6} {:>20.6e} ← total across {} sites",
"SUM", total, n_sites
);
let energy_check = 0.0_f64;
let occ = keldysh
.occupation_density(energy_check, mu_l_ne, mu_r_ne, temperature)
.expect("occupation density");
println!(
"\n Occupation density at E = {:.1} eV: {:.6e} eV⁻¹",
energy_check, occ
);
println!("\n=== Summary ===");
println!(
"NEGF transport for a {}-site tight-binding chain (t = {:.1} eV, Γ = {:.2} eV):",
n_sites,
hopping.abs(),
gamma
);
let t_at_zero = tc.transmission(0.0).expect("T(0)");
let i_at_1v = tc.current(1.0, temperature).expect("I(1V)") * ev_to_joule * 1.0e6;
println!(
" - T(E=0) = {:.4} (near-unity for clean chain)",
t_at_zero
);
println!(" - I(V=1.0 V) = {:.4} µA at T = 300 K", i_at_1v);
println!(" - G(V→0) = {:.4} G₀", g_zero_in_g0);
println!(
" - Fano factor = {:.4} (coherent, sub-Poissonian)",
fano_mid
);
println!(
" - Anderson disorder σ = {:.2} eV suppresses T(0) by factor {:.4}",
disorder_sigma, localization_factor
);
println!(" - Keldysh formalism confirms non-equilibrium carrier accumulation");
Ok(())
}