use std::collections::HashSet;
use anyhow::{anyhow, Result};
use serde::{Deserialize, Serialize};
use crate::{
core::{sequential_model::Surface, Float, RefractiveIndex},
RefractiveIndexSpec, SequentialModel, SequentialSubModel,
};
const TOL: Float = 1e-6;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Component {
Element { surf_idxs: (usize, usize) },
Stop { stop_idx: usize },
UnpairedSurface { surf_idx: usize },
}
pub fn components_view(
sequential_model: &SequentialModel,
background: RefractiveIndexSpec,
) -> Result<HashSet<Component>> {
let mut components = HashSet::new();
let surfaces = sequential_model.surfaces();
let surface_pairs = surfaces.iter().zip(surfaces.iter().skip(1)).enumerate();
let max_idx = surfaces.len() - 1;
let mut paired_surfaces = HashSet::new();
let sequential_sub_model = sequential_model
.submodels()
.values()
.next()
.ok_or(anyhow!("No submodels found in the sequential model."))?;
let gaps = sequential_sub_model.gaps();
let background_refractive_index = RefractiveIndex::try_from_spec(&background, None)?;
if max_idx < 2 {
return Ok(components);
}
for (i, surf_pair) in surface_pairs {
if i == 0 || i == max_idx {
continue;
}
if let Surface::Stop(_) = surf_pair.0 {
components.insert(Component::Stop { stop_idx: i });
continue;
}
if let Surface::Stop(_) = surf_pair.1 {
continue;
}
if same_medium(gaps[i].refractive_index, background_refractive_index) {
continue;
}
if let Surface::Image(_) = surf_pair.1 {
if !paired_surfaces.contains(&i) {
components.insert(Component::UnpairedSurface { surf_idx: i });
continue;
}
}
components.insert(Component::Element {
surf_idxs: (i, i + 1),
});
paired_surfaces.insert(i);
paired_surfaces.insert(i + 1);
}
Ok(components)
}
fn same_medium(eta_1: RefractiveIndex, eta_2: RefractiveIndex) -> bool {
(eta_1.n() - eta_2.n()).abs() < TOL && (eta_1.k() - eta_2.k()).abs() < TOL
}
#[cfg(test)]
mod tests {
use crate::{core::Float, GapSpec, RefractiveIndexSpec, SequentialModel, SurfaceSpec};
use super::*;
const AIR: RefractiveIndexSpec = RefractiveIndexSpec {
real: crate::RealSpec::Constant(1.0),
imag: None,
};
const NBK7: RefractiveIndexSpec = RefractiveIndexSpec {
real: crate::RealSpec::Constant(1.515),
imag: None,
};
pub fn empty_system() -> SequentialModel {
let surf_0 = SurfaceSpec::Object;
let gap_0 = GapSpec {
thickness: 1.0,
refractive_index: RefractiveIndexSpec {
real: crate::RealSpec::Constant(1.0),
imag: None,
},
};
let surf_1 = SurfaceSpec::Image;
let surfaces = vec![surf_0, surf_1];
let gaps = vec![gap_0];
let wavelengths = vec![0.567];
SequentialModel::new(&gaps, &surfaces, &wavelengths).unwrap()
}
pub fn silly_unpaired_surface() -> SequentialModel {
let surf_0 = SurfaceSpec::Object;
let gap_0 = GapSpec {
thickness: Float::INFINITY,
refractive_index: AIR,
};
let surf_1 = SurfaceSpec::Conic {
semi_diameter: 12.5,
radius_of_curvature: 25.8,
conic_constant: 0.0,
surf_type: crate::SurfaceType::Refracting,
};
let gap_1 = GapSpec {
thickness: 5.3,
refractive_index: NBK7,
};
let surf_2 = SurfaceSpec::Conic {
semi_diameter: 12.5,
radius_of_curvature: Float::INFINITY,
conic_constant: 0.0,
surf_type: crate::SurfaceType::Refracting,
};
let gap_2 = GapSpec {
thickness: 46.6,
refractive_index: AIR,
};
let surf_3 = SurfaceSpec::Conic {
semi_diameter: 12.5,
radius_of_curvature: 25.8,
conic_constant: 0.0,
surf_type: crate::SurfaceType::Refracting,
}; let gap_3 = GapSpec {
thickness: 20.0,
refractive_index: NBK7,
};
let surf_4 = SurfaceSpec::Image;
let surfaces = vec![surf_0, surf_1, surf_2, surf_3, surf_4];
let gaps = vec![gap_0, gap_1, gap_2, gap_3];
let wavelengths = vec![0.567];
SequentialModel::new(&gaps, &surfaces, &wavelengths).unwrap()
}
pub fn silly_single_surface_and_stop() -> SequentialModel {
let surf_0 = SurfaceSpec::Object;
let gap_0 = GapSpec {
thickness: Float::INFINITY,
refractive_index: AIR,
};
let surf_1 = SurfaceSpec::Conic {
semi_diameter: 12.5,
radius_of_curvature: 25.8,
conic_constant: 0.0,
surf_type: crate::SurfaceType::Refracting,
};
let gap_1 = GapSpec {
thickness: 10.0,
refractive_index: NBK7,
};
let surf_2 = SurfaceSpec::Stop {
semi_diameter: 12.5,
};
let gap_2 = GapSpec {
thickness: 10.0,
refractive_index: AIR,
};
let surf_3 = SurfaceSpec::Image;
let surfaces = vec![surf_0, surf_1, surf_2, surf_3];
let gaps = vec![gap_0, gap_1, gap_2];
let wavelengths = vec![0.567];
SequentialModel::new(&gaps, &surfaces, &wavelengths).unwrap()
}
pub fn wollaston_landscape_lens() -> SequentialModel {
let surf_0 = SurfaceSpec::Object;
let gap_0 = GapSpec::from_thickness_and_real_refractive_index(Float::INFINITY, 1.0);
let surf_1 = SurfaceSpec::Stop { semi_diameter: 5.0 };
let gap_1 = GapSpec::from_thickness_and_real_refractive_index(5.0, 1.0);
let surf_2 = SurfaceSpec::Conic {
semi_diameter: 6.882,
radius_of_curvature: Float::INFINITY,
conic_constant: 0.0,
surf_type: crate::SurfaceType::Refracting,
};
let gap_2 = GapSpec::from_thickness_and_real_refractive_index(5.0, 1.515);
let surf_3 = SurfaceSpec::Conic {
semi_diameter: 7.367,
radius_of_curvature: -25.84,
conic_constant: 0.0,
surf_type: crate::SurfaceType::Refracting,
};
let gap_3 = GapSpec::from_thickness_and_real_refractive_index(47.974, 1.0);
let surf_4 = SurfaceSpec::Image;
let surfaces = vec![surf_0, surf_1, surf_2, surf_3, surf_4];
let gaps = vec![gap_0, gap_1, gap_2, gap_3];
let wavelengths = vec![0.5876];
SequentialModel::new(&gaps, &surfaces, &wavelengths).unwrap()
}
#[test]
fn test_new_no_components() {
let sequential_model = empty_system();
let components = components_view(&sequential_model, AIR).unwrap();
assert_eq!(components.len(), 0);
}
#[test]
fn test_planoconvex_lens() {
let sequential_model = crate::examples::convexplano_lens::sequential_model();
let components = components_view(&sequential_model, AIR).unwrap();
assert_eq!(components.len(), 1);
assert!(components.contains(&Component::Element { surf_idxs: (1, 2) }));
}
#[test]
fn test_silly_single_surface_and_stop() {
let sequential_model = silly_single_surface_and_stop();
let components = components_view(&sequential_model, AIR).unwrap();
assert_eq!(components.len(), 1);
assert!(components.contains(&Component::Stop { stop_idx: 2 })); }
#[test]
fn test_silly_unpaired_surface() {
let sequential_model = silly_unpaired_surface();
let components = components_view(&sequential_model, AIR).unwrap();
assert_eq!(components.len(), 2);
assert!(components.contains(&Component::Element { surf_idxs: (1, 2) }));
assert!(components.contains(&Component::UnpairedSurface { surf_idx: 3 }));
}
#[test]
fn test_wollaston_landscape_lens() {
let sequential_model = wollaston_landscape_lens();
let components = components_view(&sequential_model, AIR).unwrap();
assert_eq!(components.len(), 2);
assert!(components.contains(&Component::Stop { stop_idx: 1 })); assert!(components.contains(&Component::Element { surf_idxs: (2, 3) }));
}
}