From d0c86bb070220f1e29a7c658656ef0f5ef42c39d Mon Sep 17 00:00:00 2001 From: "y.zobus" <y.zobus@gsi.de> Date: Mon, 4 Nov 2024 14:22:17 +0100 Subject: [PATCH 1/2] test: :white_check_mark: Added test for rotated and shifted paraxial lens --- opossum/examples/paraxial_lens_wavefront.rs | 26 ++--- opossum/src/nodes/paraxial_surface.rs | 117 ++++++++++++++++++-- opossum/src/ray.rs | 23 +--- 3 files changed, 123 insertions(+), 43 deletions(-) diff --git a/opossum/examples/paraxial_lens_wavefront.rs b/opossum/examples/paraxial_lens_wavefront.rs index 0abb911a..488751ee 100644 --- a/opossum/examples/paraxial_lens_wavefront.rs +++ b/opossum/examples/paraxial_lens_wavefront.rs @@ -2,27 +2,27 @@ use std::path::Path; use num::Zero; use opossum::{ - analyzers::{AnalyzerType, RayTraceConfig}, - error::OpmResult, - joule, millimeter, - nodes::{ - round_collimated_ray_source, NodeGroup, ParaxialSurface, RayPropagationVisualizer, - WaveFront, - }, - OpmDocument, + analyzers::{AnalyzerType, RayTraceConfig}, degree, error::OpmResult, joule, millimeter, nodes::{ + collimated_line_ray_source, round_collimated_ray_source, NodeGroup, ParaxialSurface, RayPropagationVisualizer, WaveFront + }, optic_node::OpticNode, utils::geom_transformation::Isometry, OpmDocument }; use uom::si::f64::Length; fn main() -> OpmResult<()> { let mut scenery = NodeGroup::new("Lens Ray-trace test"); let src = scenery - .add_node(&round_collimated_ray_source(millimeter!(5.0), joule!(1.0), 30).unwrap())?; - let lens = scenery.add_node(&ParaxialSurface::new("f=100 mm", millimeter!(100.0))?)?; - let wf = scenery.add_node(&WaveFront::default())?; + .add_node(&collimated_line_ray_source(millimeter!(f64::sqrt(2.)*100.0), joule!(1.0), 10).unwrap())?; + let mut lens = ParaxialSurface::new("f=100 mm", millimeter!(100.0))?; + lens.set_isometry( + Isometry::new(millimeter!(0.0, 0.0, 100.0), degree!(45.0, 0.0, 0.0)).unwrap(), + ); + let lens = scenery.add_node(&lens)?; + + // let wf = scenery.add_node(&WaveFront::default())?; let det = scenery.add_node(&RayPropagationVisualizer::default())?; scenery.connect_nodes(src, "output_1", lens, "input_1", Length::zero())?; - scenery.connect_nodes(lens, "output_1", wf, "input_1", millimeter!(90.0))?; - scenery.connect_nodes(wf, "output_1", det, "input_1", Length::zero())?; + scenery.connect_nodes(lens, "output_1", det, "input_1", millimeter!(300.0))?; + // scenery.connect_nodes(wf, "output_1", det, "input_1", Length::zero())?; let mut doc = OpmDocument::new(scenery); doc.add_analyzer(AnalyzerType::RayTrace(RayTraceConfig::default())); diff --git a/opossum/src/nodes/paraxial_surface.rs b/opossum/src/nodes/paraxial_surface.rs index ffff1c31..f1675d5f 100644 --- a/opossum/src/nodes/paraxial_surface.rs +++ b/opossum/src/nodes/paraxial_surface.rs @@ -181,6 +181,7 @@ mod test { nodes::test_helper::test_helper::*, optic_ports::PortType, ray::Ray, rays::Rays, utils::geom_transformation::Isometry, }; + use approx::assert_relative_eq; use assert_matches::assert_matches; use nalgebra::Vector3; #[test] @@ -255,7 +256,7 @@ mod test { test_analyze_wrong_data_type::<ParaxialSurface>("input_1"); } #[test] - fn analyze_geometric_no_isometery() { + fn analyze_geometric_no_isometry() { test_analyze_geometric_no_isometry::<ParaxialSurface>("input_1"); } #[test] @@ -283,13 +284,113 @@ mod test { assert!(false, "could not get LightData"); } } - // #[test] - // #[ignore] - // fn export_data() { - // assert!(ParaxialSurface::default() - // .export_data(Path::new("")) - // .is_ok()); - // } + #[test] + fn test_shifted_x(){ + let mut node = ParaxialSurface::new("test", millimeter!(10.)).unwrap(); + node.set_isometry( + Isometry::new(millimeter!(10.0, 0.0, 10.0), degree!(0.0, 0.0, 0.0)).unwrap(), + ); + let mut rays = Rays::default(); + rays.add_ray( + Ray::new_collimated(millimeter!(0.0, 0.0, 0.0), nanometer!(1000.0), joule!(1.0)) + .unwrap(), + ); + let mut input = LightResult::default(); + input.insert("input_1".into(), LightData::Geometric(rays)); + let output = + AnalysisRayTrace::analyze(&mut node, input, &RayTraceConfig::default()).unwrap(); + + if let Some(LightData::Geometric(rays)) = output.get("output_1") { + assert_eq!(rays.nr_of_rays(true), 1); + let ray = rays.iter().next().unwrap(); + assert_eq!(ray.position(), millimeter!(0.0, 0.0, 10.0)); + assert_eq!(ray.direction(), Vector3::new(1.,0.,1.)); + } else { + assert!(false, "could not get LightData"); + } + } + #[test] + fn test_shifted_y(){ + let mut node = ParaxialSurface::new("test", millimeter!(10.)).unwrap(); + node.set_isometry( + Isometry::new(millimeter!(0.0, 10.0, 10.0), degree!(0.0, 0.0, 0.0)).unwrap(), + ); + let mut rays = Rays::default(); + rays.add_ray( + Ray::new_collimated(millimeter!(0.0, 0.0, 0.0), nanometer!(1000.0), joule!(1.0)) + .unwrap(), + ); + let mut input = LightResult::default(); + input.insert("input_1".into(), LightData::Geometric(rays)); + let output = + AnalysisRayTrace::analyze(&mut node, input, &RayTraceConfig::default()).unwrap(); + + if let Some(LightData::Geometric(rays)) = output.get("output_1") { + assert_eq!(rays.nr_of_rays(true), 1); + let ray = rays.iter().next().unwrap(); + assert_eq!(ray.position(), millimeter!(0.0, 0.0, 10.0)); + assert_eq!(ray.direction(), Vector3::new(0.,1.,1.)); + } else { + assert!(false, "could not get LightData"); + } + } + + #[test] + fn test_rotated_y(){ + let mut node = ParaxialSurface::new("test", millimeter!(10.)).unwrap(); + node.set_isometry( + Isometry::new(millimeter!(0.0, 0.0, 10.0), degree!(45.0, 0.0, 0.0)).unwrap(), + ); + let mut rays = Rays::default(); + rays.add_ray( + Ray::new_collimated(millimeter!(0.0, 10.0/f64::sqrt(2.), 0.0), nanometer!(1000.0), joule!(1.0)) + .unwrap(), + ); + let mut input = LightResult::default(); + input.insert("input_1".into(), LightData::Geometric(rays)); + let output = + AnalysisRayTrace::analyze(&mut node, input, &RayTraceConfig::default()).unwrap(); + + if let Some(LightData::Geometric(rays)) = output.get("output_1") { + assert_eq!(rays.nr_of_rays(true), 1); + let ray = rays.iter().next().unwrap(); + assert_relative_eq!(ray.position()[0].value, 0.0); + assert_relative_eq!(ray.position()[1].value, 0.01/f64::sqrt(2.)); + assert_relative_eq!(ray.position()[2].value, 0.01/f64::sqrt(2.)+0.01); + assert_relative_eq!(ray.direction(), Vector3::new(0.,-1.,1.).normalize()); + } else { + assert!(false, "could not get LightData"); + } + } + + #[test] + fn test_rotated_x(){ + let mut node = ParaxialSurface::new("test", millimeter!(10.)).unwrap(); + node.set_isometry( + Isometry::new(millimeter!(0.0, 0.0, 10.0), degree!(0.0, 45.0, 0.0)).unwrap(), + ); + let mut rays = Rays::default(); + rays.add_ray( + Ray::new_collimated(millimeter!(-10.0/f64::sqrt(2.), 0.0, 0.0), nanometer!(1000.0), joule!(1.0)) + .unwrap(), + ); + let mut input = LightResult::default(); + input.insert("input_1".into(), LightData::Geometric(rays)); + let output = + AnalysisRayTrace::analyze(&mut node, input, &RayTraceConfig::default()).unwrap(); + + if let Some(LightData::Geometric(rays)) = output.get("output_1") { + assert_eq!(rays.nr_of_rays(true), 1); + let ray = rays.iter().next().unwrap(); + assert_relative_eq!(ray.position()[0].value, -0.01/f64::sqrt(2.)); + assert_relative_eq!(ray.position()[1].value, 0.0); + assert_relative_eq!(ray.position()[2].value, 0.01/f64::sqrt(2.)+0.01); + assert_relative_eq!(ray.direction(), Vector3::new(1.,0.,1.).normalize()); + } else { + assert!(false, "could not get LightData"); + } + } + #[test] fn as_ref_node_mut() { let mut node = ParaxialSurface::default(); diff --git a/opossum/src/ray.rs b/opossum/src/ray.rs index 770df717..cadabd30 100644 --- a/opossum/src/ray.rs +++ b/opossum/src/ray.rs @@ -302,28 +302,7 @@ impl Ray { pub fn to_isometry(&self, up_direction: Vector3<f64>) -> Isometry { Isometry::new_from_view(self.position(), self.direction(), up_direction) } - /// Propagate a ray freely along its direction. The length is given as the projection on the z-axis (=optical axis). - /// - /// This function also respects the refractive index stored in the ray while calculating the optical path length. - /// - /// # Errors - /// This functions returns an error if the initial ray direction has a zero z component (= ray not propagating in z direction). - // pub fn propagate_along_z(&mut self, length_along_z: Length) -> OpmResult<()> { - // if self.dir[2].abs() < f64::EPSILON { - // return Err(OpossumError::Other( - // "z-Axis of direction vector must be != 0.0".into(), - // )); - // } - // self.pos_hist.push(self.pos); - // let length_in_ray_dir = length_along_z / self.dir[2]; - // self.pos += vector![ - // length_in_ray_dir * self.dir.x, - // length_in_ray_dir * self.dir.y, - // length_in_ray_dir * self.dir.z - // ]; - // self.path_length += length_in_ray_dir * self.refractive_index * self.dir.norm(); - // Ok(()) - // } + /// Refract a ray on a paraxial surface of a given focal length. /// /// Modify the ray direction in order to simulate a perfect lens. **Note**: This function also -- GitLab From 3508b44c3e65354b1ed6dfe7429b5c1d05493432 Mon Sep 17 00:00:00 2001 From: "y.zobus" <y.zobus@gsi.de> Date: Mon, 4 Nov 2024 14:24:21 +0100 Subject: [PATCH 2/2] cargo fmt + cargo xtask ci --- opossum/examples/paraxial_lens_wavefront.rs | 26 +++--- opossum/src/nodes/paraxial_surface.rs | 96 +++++++++++---------- 2 files changed, 65 insertions(+), 57 deletions(-) diff --git a/opossum/examples/paraxial_lens_wavefront.rs b/opossum/examples/paraxial_lens_wavefront.rs index 488751ee..0abb911a 100644 --- a/opossum/examples/paraxial_lens_wavefront.rs +++ b/opossum/examples/paraxial_lens_wavefront.rs @@ -2,27 +2,27 @@ use std::path::Path; use num::Zero; use opossum::{ - analyzers::{AnalyzerType, RayTraceConfig}, degree, error::OpmResult, joule, millimeter, nodes::{ - collimated_line_ray_source, round_collimated_ray_source, NodeGroup, ParaxialSurface, RayPropagationVisualizer, WaveFront - }, optic_node::OpticNode, utils::geom_transformation::Isometry, OpmDocument + analyzers::{AnalyzerType, RayTraceConfig}, + error::OpmResult, + joule, millimeter, + nodes::{ + round_collimated_ray_source, NodeGroup, ParaxialSurface, RayPropagationVisualizer, + WaveFront, + }, + OpmDocument, }; use uom::si::f64::Length; fn main() -> OpmResult<()> { let mut scenery = NodeGroup::new("Lens Ray-trace test"); let src = scenery - .add_node(&collimated_line_ray_source(millimeter!(f64::sqrt(2.)*100.0), joule!(1.0), 10).unwrap())?; - let mut lens = ParaxialSurface::new("f=100 mm", millimeter!(100.0))?; - lens.set_isometry( - Isometry::new(millimeter!(0.0, 0.0, 100.0), degree!(45.0, 0.0, 0.0)).unwrap(), - ); - let lens = scenery.add_node(&lens)?; - - // let wf = scenery.add_node(&WaveFront::default())?; + .add_node(&round_collimated_ray_source(millimeter!(5.0), joule!(1.0), 30).unwrap())?; + let lens = scenery.add_node(&ParaxialSurface::new("f=100 mm", millimeter!(100.0))?)?; + let wf = scenery.add_node(&WaveFront::default())?; let det = scenery.add_node(&RayPropagationVisualizer::default())?; scenery.connect_nodes(src, "output_1", lens, "input_1", Length::zero())?; - scenery.connect_nodes(lens, "output_1", det, "input_1", millimeter!(300.0))?; - // scenery.connect_nodes(wf, "output_1", det, "input_1", Length::zero())?; + scenery.connect_nodes(lens, "output_1", wf, "input_1", millimeter!(90.0))?; + scenery.connect_nodes(wf, "output_1", det, "input_1", Length::zero())?; let mut doc = OpmDocument::new(scenery); doc.add_analyzer(AnalyzerType::RayTrace(RayTraceConfig::default())); diff --git a/opossum/src/nodes/paraxial_surface.rs b/opossum/src/nodes/paraxial_surface.rs index f1675d5f..2abee2af 100644 --- a/opossum/src/nodes/paraxial_surface.rs +++ b/opossum/src/nodes/paraxial_surface.rs @@ -285,7 +285,7 @@ mod test { } } #[test] - fn test_shifted_x(){ + fn test_shifted_x() { let mut node = ParaxialSurface::new("test", millimeter!(10.)).unwrap(); node.set_isometry( Isometry::new(millimeter!(10.0, 0.0, 10.0), degree!(0.0, 0.0, 0.0)).unwrap(), @@ -300,17 +300,17 @@ mod test { let output = AnalysisRayTrace::analyze(&mut node, input, &RayTraceConfig::default()).unwrap(); - if let Some(LightData::Geometric(rays)) = output.get("output_1") { - assert_eq!(rays.nr_of_rays(true), 1); - let ray = rays.iter().next().unwrap(); - assert_eq!(ray.position(), millimeter!(0.0, 0.0, 10.0)); - assert_eq!(ray.direction(), Vector3::new(1.,0.,1.)); - } else { - assert!(false, "could not get LightData"); - } + if let Some(LightData::Geometric(rays)) = output.get("output_1") { + assert_eq!(rays.nr_of_rays(true), 1); + let ray = rays.iter().next().unwrap(); + assert_eq!(ray.position(), millimeter!(0.0, 0.0, 10.0)); + assert_eq!(ray.direction(), Vector3::new(1., 0., 1.)); + } else { + assert!(false, "could not get LightData"); + } } #[test] - fn test_shifted_y(){ + fn test_shifted_y() { let mut node = ParaxialSurface::new("test", millimeter!(10.)).unwrap(); node.set_isometry( Isometry::new(millimeter!(0.0, 10.0, 10.0), degree!(0.0, 0.0, 0.0)).unwrap(), @@ -325,70 +325,78 @@ mod test { let output = AnalysisRayTrace::analyze(&mut node, input, &RayTraceConfig::default()).unwrap(); - if let Some(LightData::Geometric(rays)) = output.get("output_1") { - assert_eq!(rays.nr_of_rays(true), 1); - let ray = rays.iter().next().unwrap(); - assert_eq!(ray.position(), millimeter!(0.0, 0.0, 10.0)); - assert_eq!(ray.direction(), Vector3::new(0.,1.,1.)); - } else { - assert!(false, "could not get LightData"); - } + if let Some(LightData::Geometric(rays)) = output.get("output_1") { + assert_eq!(rays.nr_of_rays(true), 1); + let ray = rays.iter().next().unwrap(); + assert_eq!(ray.position(), millimeter!(0.0, 0.0, 10.0)); + assert_eq!(ray.direction(), Vector3::new(0., 1., 1.)); + } else { + assert!(false, "could not get LightData"); + } } #[test] - fn test_rotated_y(){ + fn test_rotated_y() { let mut node = ParaxialSurface::new("test", millimeter!(10.)).unwrap(); node.set_isometry( Isometry::new(millimeter!(0.0, 0.0, 10.0), degree!(45.0, 0.0, 0.0)).unwrap(), ); let mut rays = Rays::default(); rays.add_ray( - Ray::new_collimated(millimeter!(0.0, 10.0/f64::sqrt(2.), 0.0), nanometer!(1000.0), joule!(1.0)) - .unwrap(), + Ray::new_collimated( + millimeter!(0.0, 10.0 / f64::sqrt(2.), 0.0), + nanometer!(1000.0), + joule!(1.0), + ) + .unwrap(), ); let mut input = LightResult::default(); input.insert("input_1".into(), LightData::Geometric(rays)); let output = AnalysisRayTrace::analyze(&mut node, input, &RayTraceConfig::default()).unwrap(); - if let Some(LightData::Geometric(rays)) = output.get("output_1") { - assert_eq!(rays.nr_of_rays(true), 1); - let ray = rays.iter().next().unwrap(); - assert_relative_eq!(ray.position()[0].value, 0.0); - assert_relative_eq!(ray.position()[1].value, 0.01/f64::sqrt(2.)); - assert_relative_eq!(ray.position()[2].value, 0.01/f64::sqrt(2.)+0.01); - assert_relative_eq!(ray.direction(), Vector3::new(0.,-1.,1.).normalize()); - } else { - assert!(false, "could not get LightData"); - } + if let Some(LightData::Geometric(rays)) = output.get("output_1") { + assert_eq!(rays.nr_of_rays(true), 1); + let ray = rays.iter().next().unwrap(); + assert_relative_eq!(ray.position()[0].value, 0.0); + assert_relative_eq!(ray.position()[1].value, 0.01 / f64::sqrt(2.)); + assert_relative_eq!(ray.position()[2].value, 0.01 / f64::sqrt(2.) + 0.01); + assert_relative_eq!(ray.direction(), Vector3::new(0., -1., 1.).normalize()); + } else { + assert!(false, "could not get LightData"); + } } #[test] - fn test_rotated_x(){ + fn test_rotated_x() { let mut node = ParaxialSurface::new("test", millimeter!(10.)).unwrap(); node.set_isometry( Isometry::new(millimeter!(0.0, 0.0, 10.0), degree!(0.0, 45.0, 0.0)).unwrap(), ); let mut rays = Rays::default(); rays.add_ray( - Ray::new_collimated(millimeter!(-10.0/f64::sqrt(2.), 0.0, 0.0), nanometer!(1000.0), joule!(1.0)) - .unwrap(), + Ray::new_collimated( + millimeter!(-10.0 / f64::sqrt(2.), 0.0, 0.0), + nanometer!(1000.0), + joule!(1.0), + ) + .unwrap(), ); let mut input = LightResult::default(); input.insert("input_1".into(), LightData::Geometric(rays)); let output = AnalysisRayTrace::analyze(&mut node, input, &RayTraceConfig::default()).unwrap(); - if let Some(LightData::Geometric(rays)) = output.get("output_1") { - assert_eq!(rays.nr_of_rays(true), 1); - let ray = rays.iter().next().unwrap(); - assert_relative_eq!(ray.position()[0].value, -0.01/f64::sqrt(2.)); - assert_relative_eq!(ray.position()[1].value, 0.0); - assert_relative_eq!(ray.position()[2].value, 0.01/f64::sqrt(2.)+0.01); - assert_relative_eq!(ray.direction(), Vector3::new(1.,0.,1.).normalize()); - } else { - assert!(false, "could not get LightData"); - } + if let Some(LightData::Geometric(rays)) = output.get("output_1") { + assert_eq!(rays.nr_of_rays(true), 1); + let ray = rays.iter().next().unwrap(); + assert_relative_eq!(ray.position()[0].value, -0.01 / f64::sqrt(2.)); + assert_relative_eq!(ray.position()[1].value, 0.0); + assert_relative_eq!(ray.position()[2].value, 0.01 / f64::sqrt(2.) + 0.01); + assert_relative_eq!(ray.direction(), Vector3::new(1., 0., 1.).normalize()); + } else { + assert!(false, "could not get LightData"); + } } #[test] -- GitLab