From 4557fe7902924db2971296da52760dbe649443c1 Mon Sep 17 00:00:00 2001
From: "y.zobus" <y.zobus@gsi.de>
Date: Fri, 21 Jul 2023 16:04:33 +0200
Subject: [PATCH] added lens node

---
 examples/lens_test.rs  |  25 +++++++
 src/nodes/node_lens.rs | 153 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 178 insertions(+)
 create mode 100644 examples/lens_test.rs
 create mode 100644 src/nodes/node_lens.rs

diff --git a/examples/lens_test.rs b/examples/lens_test.rs
new file mode 100644
index 00000000..a8c6571c
--- /dev/null
+++ b/examples/lens_test.rs
@@ -0,0 +1,25 @@
+use opossum::{
+    nodes::{RealLens, Source, Detector},
+    optic_scenery::OpticScenery, error::OpossumError,
+};
+use std::fs::File;
+use std::io::Write;
+
+fn main() -> Result<(), OpossumError> {
+    let mut scenery = OpticScenery::new();
+    scenery.set_description("Lens Ray-trace test".into());
+    let src = scenery.add_element("Source", Source::default());
+    let l1 = scenery.add_element("Lens 1", RealLens::default());
+    let l2 = scenery.add_element("Lens 2", RealLens::default());
+    let det=scenery.add_element("Detector", Detector::default());
+
+    scenery.connect_nodes(src, "out1", l1, "in1")?;
+    scenery.connect_nodes(l1, "out1", l2, "in1")?;
+    scenery.connect_nodes(l2, "out1", det, "in1")?;
+
+
+    let path = "lens_system.dot";
+    let mut output = File::create(path).unwrap();
+    write!(output, "{}", scenery.to_dot()).unwrap();
+    Ok(())
+}
diff --git a/src/nodes/node_lens.rs b/src/nodes/node_lens.rs
new file mode 100644
index 00000000..8be6263b
--- /dev/null
+++ b/src/nodes/node_lens.rs
@@ -0,0 +1,153 @@
+use std::collections::HashMap;
+use uom::{si::f64::{Energy, Length}, si::length::meter, num_traits::Zero};
+use ndarray::{Array1, Array2, array};
+
+type Result<T> = std::result::Result<T, OpossumError>;
+
+
+use crate::{
+    analyzer::AnalyzerType,
+    error::OpossumError,
+    lightdata::{LightData, DataEnergy, RayDataParaxial},
+    optic_node::{Dottable, LightResult, Optical},
+    optic_ports::OpticPorts,
+};
+
+pub struct IdealLens {
+    focal_length: f64,
+    aperture: f64
+}
+#[derive(Debug)]
+pub struct RealLens {
+    aperture: Length,
+    curvatures: Array1<Length>,
+    center_thickness: Length,
+    z_pos: Length,    
+    refractive_index: f64,
+}
+
+
+impl RealLens {
+    pub fn new(aperture: Length, front_curvature: Length, rear_curvature: Length, center_thickness: Length, z_pos: Length, refractive_index: f64) -> Self {
+        Self{   aperture: aperture,
+                curvatures: array![front_curvature,rear_curvature],
+                center_thickness: center_thickness,
+                z_pos: z_pos,   
+                refractive_index: refractive_index,
+        }
+    }
+
+    pub fn get_aperture(&self) -> Length{
+        self.aperture
+    }
+
+    pub fn set_aperture(&mut self, aperture: f64) {
+        self.aperture = Length::new::<meter>(aperture);
+    }
+
+    pub fn get_curvatures(&self) -> &Array1<Length>{
+        &self.curvatures
+    }    
+
+    pub fn set_curvatures(&mut self, curvature_1: f64, curvature_2: f64) {
+        self.curvatures = array![Length::new::<meter>(curvature_1),Length::new::<meter>(curvature_2)];
+    }
+
+    pub fn get_thickness(&self) -> Length{
+        self.center_thickness
+    }
+
+    pub fn set_thickness(&mut self, thickness: f64) {
+        self.center_thickness = Length::new::<meter>(thickness);
+    }
+
+    pub fn get_position(&self) -> Length{
+        self.z_pos
+    }
+
+    pub fn set_position(&mut self, position: f64) {
+        self.z_pos = Length::new::<meter>(position);
+    }
+
+    pub fn get_refractve_index(&self) -> f64{
+        self.refractive_index
+    }
+
+    pub fn set_refractve_index(&mut self, refractive_index: f64) {
+        self.refractive_index = refractive_index;
+    }
+
+    fn analyze_ray_trace(&mut self, incoming_data: LightResult) -> Result<LightResult> {
+        let in1: Option<&Option<LightData>> = incoming_data.get("in1");
+        Ok(incoming_data)
+
+        // let mut in_rays: Vec<RayDataParaxial> = Vec::new();
+        // if let Some(Some(in1)) = in1 {
+        //     match in1 {
+        //         LightData::ParAxialRayTrace(rays) => in_rays = rays.rays,
+        //         _ => return Err(OpossumError::Analysis("expected set of rays".into())),
+        //     }
+        // };
+
+        // let out1_energy = Some(LightData::Energy(DataEnergy {
+        //     energy: in1_energy * self.ratio + in2_energy * (1.0 - self.ratio),
+        // }));
+        // Ok(HashMap::from([
+        //     ("out1_trans1_refl2".into(), out1_energy),
+        //     ("out2_trans2_refl1".into(), out2_energy),
+        // ]))
+    }
+
+    // fn ray_propagate(&mut self, rays: &mut Vec<RayDataParaxial>){
+    //     for ray in rays.into_iter(){
+    //         if ray.pos
+    //     };
+    // }
+
+    // pub struct RayDataParaxial {
+    //     // ray: Array1<f64>,
+    //     ray: Array1<f64>,
+    //     pos: Vec<[f64;3]>,
+    //     index: usize,
+    //     bounce_lvl: usize,
+    //     max_bounces: usize,
+    // }
+
+}
+
+impl Default for RealLens {
+    /// Create a 100mm focal lengths lens. LA1251-B from thorlabs. refractive inde hardcoded for n-bk7 at 1054 nm
+    fn default() -> Self {
+        Self {  aperture: Length::new::<meter>(25e-3),
+                curvatures: array![Length::new::<meter>(51.5e-3),Length::new::<meter>(f64::INFINITY)],
+                center_thickness: Length::new::<meter>(3.6e-3),
+                z_pos: Length::new::<meter>(0.0),   
+                refractive_index: 1.5068}
+    }
+}
+
+impl Optical for RealLens {
+    fn node_type(&self) -> &str {
+        "real lens"
+    }
+    fn ports(&self) -> OpticPorts {
+        let mut ports = OpticPorts::new();
+        ports.add_input("in1").unwrap();
+        ports.add_output("out1").unwrap();
+        ports
+    }
+
+    fn analyze(&mut self, incoming_data: LightResult, analyzer_type: &AnalyzerType) -> Result<LightResult> {
+        match analyzer_type {
+            AnalyzerType::Energy => Err(OpossumError::Analysis("Energy Analysis is not yet implemented for Lens Nodes".into())),
+            AnalyzerType::ParAxialRayTrace => self.analyze_ray_trace(incoming_data),
+        }
+    }    
+}
+
+
+impl Dottable for RealLens {
+    fn node_color(&self) -> &str {
+        "blue"
+    }
+}
-- 
GitLab