use std::f64::consts::PI;
#[derive(Debug, Clone)]
pub struct PendrySuperLens {
pub slab_thickness_m: f64,
pub eps_slab: f64,
pub wavelength_m: f64,
}
impl PendrySuperLens {
pub fn k0(&self) -> f64 {
2.0 * PI / self.wavelength_m.max(1e-30)
}
pub fn evanescent_amplification(&self, kx_over_k0: f64) -> f64 {
let k0 = self.k0();
let kx = kx_over_k0 * k0;
if kx_over_k0.abs() <= 1.0 {
1.0
} else {
let kappa = (kx * kx - k0 * k0).max(0.0).sqrt();
(kappa * self.slab_thickness_m).exp()
}
}
pub fn resolution_m(&self, eps_imag: f64) -> f64 {
let eps_im = eps_imag.abs().max(1e-30);
let kappa_max_d = (-eps_im.ln()).max(1e-10);
let kappa_max = kappa_max_d / self.slab_thickness_m.max(1e-30);
PI / kappa_max
}
pub fn image_distance_m(&self) -> f64 {
self.slab_thickness_m / 2.0
}
pub fn magnification(&self) -> f64 {
1.0
}
pub fn max_spatial_frequency_k0(&self, eps_imag: f64) -> f64 {
let eps_im = eps_imag.abs().max(1e-30);
let kappa_max_d = (-eps_im.ln()).max(1e-10);
let kappa_max = kappa_max_d / self.slab_thickness_m.max(1e-30);
let k0 = self.k0();
kappa_max / k0
}
pub fn is_near_perfect_lens(&self, tolerance: f64) -> bool {
(self.eps_slab + 1.0).abs() < tolerance
}
}
#[derive(Debug, Clone)]
pub struct OpticalHyperlens {
pub inner_radius_m: f64,
pub outer_radius_m: f64,
pub eps_radial: f64,
pub eps_tangential: f64,
pub wavelength_m: f64,
}
impl OpticalHyperlens {
pub fn magnification(&self) -> f64 {
self.outer_radius_m / self.inner_radius_m.max(1e-30)
}
pub fn is_hyperbolic(&self) -> bool {
self.eps_radial * self.eps_tangential < 0.0
}
pub fn inner_surface_resolution_m(&self) -> f64 {
if self.eps_radial.abs() < 1e-30 {
return f64::INFINITY;
}
let factor = (self.eps_tangential.abs() / self.eps_radial.abs()).sqrt();
self.wavelength_m / (2.0 * factor.max(1e-30))
}
pub fn outer_surface_resolution_m(&self) -> f64 {
self.wavelength_m / (2.0 * self.magnification().max(1e-30))
}
pub fn max_spatial_frequency(&self) -> f64 {
(self.eps_tangential.abs() / self.eps_radial.abs().max(1e-30)).sqrt()
}
pub fn is_in_hyperbolic_regime(&self) -> bool {
self.is_hyperbolic()
}
pub fn resolution_enhancement_factor(&self) -> f64 {
if self.eps_radial.abs() < 1e-30 {
return f64::INFINITY;
}
(self.eps_tangential.abs() / self.eps_radial.abs()).sqrt()
}
pub fn effective_numerical_aperture(&self) -> f64 {
let ratio = (self.eps_tangential.abs() / self.eps_radial.abs().max(1e-30)).sqrt();
ratio * self.inner_radius_m / self.outer_radius_m.max(1e-30)
}
pub fn phase_accumulation_rad(&self) -> f64 {
let k0 = 2.0 * PI / self.wavelength_m.max(1e-30);
let n_eff = self.eps_tangential.abs().sqrt();
k0 * n_eff * (self.outer_radius_m - self.inner_radius_m).abs()
}
}
#[derive(Debug, Clone)]
pub struct SphericalSuperlens {
pub r1_m: f64,
pub r2_m: f64,
pub eps_shell: f64,
pub mu_shell: f64,
pub wavelength_m: f64,
}
impl SphericalSuperlens {
pub fn refractive_index(&self) -> f64 {
let sign = if self.eps_shell < 0.0 && self.mu_shell < 0.0 {
-1.0
} else {
1.0
};
sign * (self.eps_shell.abs() * self.mu_shell.abs()).sqrt()
}
pub fn is_double_negative(&self) -> bool {
self.eps_shell < 0.0 && self.mu_shell < 0.0
}
pub fn geometric_magnification(&self) -> f64 {
self.r2_m / self.r1_m.max(1e-30)
}
pub fn solid_angle_sr(&self) -> f64 {
4.0 * PI
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn hyperlens_magnification() {
let hl = OpticalHyperlens {
inner_radius_m: 250e-9,
outer_radius_m: 500e-9,
eps_radial: -3.0,
eps_tangential: 4.0,
wavelength_m: 365e-9,
};
assert!(
(hl.magnification() - 2.0).abs() < 1e-10,
"Magnification should be 2.0, got {}",
hl.magnification()
);
assert!(
hl.is_hyperbolic(),
"Should be hyperbolic (ε_r < 0, ε_θ > 0)"
);
}
#[test]
fn hyperlens_inner_resolution() {
let hl = OpticalHyperlens {
inner_radius_m: 250e-9,
outer_radius_m: 500e-9,
eps_radial: -3.0,
eps_tangential: 4.0,
wavelength_m: 365e-9,
};
let res = hl.inner_surface_resolution_m();
assert!(
res < hl.wavelength_m / 2.0,
"Inner resolution {} should be sub-diffraction",
res
);
}
#[test]
fn superlens_evanescent_amplification_propagating() {
let sl = PendrySuperLens {
slab_thickness_m: 40e-9,
eps_slab: -1.0,
wavelength_m: 365e-9,
};
let amp = sl.evanescent_amplification(0.5);
assert!(
(amp - 1.0).abs() < 1e-10,
"Propagating amp should be 1.0, got {}",
amp
);
}
#[test]
fn superlens_evanescent_amplification_grows() {
let sl = PendrySuperLens {
slab_thickness_m: 40e-9,
eps_slab: -1.0,
wavelength_m: 365e-9,
};
let amp_low = sl.evanescent_amplification(2.0);
let amp_high = sl.evanescent_amplification(4.0);
assert!(
amp_high > amp_low,
"Higher kx should give more amplification"
);
}
#[test]
fn superlens_resolution_improves_with_less_loss() {
let sl1 = PendrySuperLens {
slab_thickness_m: 40e-9,
eps_slab: -1.0,
wavelength_m: 365e-9,
};
let sl2 = PendrySuperLens {
slab_thickness_m: 40e-9,
eps_slab: -1.0,
wavelength_m: 365e-9,
};
let res_low_loss = sl1.resolution_m(0.01);
let res_high_loss = sl2.resolution_m(0.1);
assert!(
res_low_loss < res_high_loss,
"Lower loss should give finer resolution"
);
}
#[test]
fn superlens_image_distance() {
let sl = PendrySuperLens {
slab_thickness_m: 80e-9,
eps_slab: -1.0,
wavelength_m: 365e-9,
};
assert!((sl.image_distance_m() - 40e-9).abs() < 1e-20);
assert_eq!(sl.magnification(), 1.0);
}
#[test]
fn spherical_superlens_double_negative() {
let ssl = SphericalSuperlens {
r1_m: 100e-9,
r2_m: 200e-9,
eps_shell: -1.5,
mu_shell: -1.0,
wavelength_m: 532e-9,
};
assert!(ssl.is_double_negative());
assert!(ssl.refractive_index() < 0.0, "n should be negative for DNM");
}
#[test]
fn hyperlens_max_spatial_frequency() {
let hl = OpticalHyperlens {
inner_radius_m: 150e-9,
outer_radius_m: 450e-9,
eps_radial: -2.0,
eps_tangential: 3.0,
wavelength_m: 400e-9,
};
let kmax = hl.max_spatial_frequency();
assert!(
(kmax - (1.5_f64).sqrt()).abs() < 1e-10,
"k_max should be √(3/2), got {}",
kmax
);
}
}