From 1e63bfc4c6eb1160eba67ca049c195dd1d20734d Mon Sep 17 00:00:00 2001
From: "y.zobus" <y.zobus@gsi.de>
Date: Fri, 25 Oct 2024 10:47:14 +0000
Subject: [PATCH] * xtask

* feat: :sparkles: Added the possibility to add lidt of an optic on creation

* correctly deserialize lidt

* implemented get_surface_mut for thin mirror, paraxial surface and reflective grating

* added LIDT trait for nodes

* fixed error when last element was lens, wedge or cylindric lens

* include surface trait in Opticnode
---
 opossum/examples/ghost_focus.rs               | 31 +++---
 opossum/files_for_testing/opm/optic_ref.opm   |  1 +
 .../files_for_testing/opm/opticscenery.opm    |  3 +
 opossum/src/analyzers/analyzable.rs           |  5 +-
 opossum/src/analyzers/ghostfocus.rs           | 14 +--
 opossum/src/analyzers/raytrace.rs             |  3 +-
 opossum/src/nodes/beam_splitter/mod.rs        | 12 +--
 .../cylindric_lens/analysis_ghostfocus.rs     |  7 +-
 opossum/src/nodes/cylindric_lens/mod.rs       | 29 +++---
 opossum/src/nodes/detector.rs                 | 14 +--
 opossum/src/nodes/dummy.rs                    | 15 +--
 opossum/src/nodes/energy_meter.rs             | 10 +-
 opossum/src/nodes/fluence_detector.rs         | 42 ++------
 opossum/src/nodes/ideal_filter.rs             | 13 ++-
 opossum/src/nodes/lens/analysis_ghostfocus.rs |  8 +-
 opossum/src/nodes/lens/mod.rs                 | 60 ++++++-----
 opossum/src/nodes/node_attr.rs                | 15 +++
 opossum/src/nodes/node_group/mod.rs           |  5 +-
 opossum/src/nodes/paraxial_surface.rs         | 99 ++++++++++---------
 .../src/nodes/ray_propagation_visualizer.rs   | 14 +--
 opossum/src/nodes/reference.rs                | 19 ++--
 opossum/src/nodes/reflective_grating.rs       | 34 ++++---
 opossum/src/nodes/source.rs                   | 23 ++---
 opossum/src/nodes/spectrometer.rs             |  9 +-
 opossum/src/nodes/spot_diagram.rs             | 14 ++-
 opossum/src/nodes/thin_mirror.rs              | 56 ++++++-----
 opossum/src/nodes/wavefront.rs                | 14 +--
 .../src/nodes/wedge/analysis_ghostfocus.rs    |  9 +-
 opossum/src/nodes/wedge/mod.rs                | 22 ++---
 opossum/src/opm_document.rs                   |  1 +
 opossum/src/optic_node.rs                     | 49 ++++++++-
 opossum/src/ray.rs                            |  9 +-
 opossum/src/rays.rs                           |  4 +-
 opossum/src/surface/hit_map.rs                | 18 +---
 opossum/src/surface/mod.rs                    |  6 --
 opossum/src/surface/optical_surface.rs        | 19 +++-
 36 files changed, 374 insertions(+), 332 deletions(-)

diff --git a/opossum/examples/ghost_focus.rs b/opossum/examples/ghost_focus.rs
index 8d7ce67b..13c76e13 100644
--- a/opossum/examples/ghost_focus.rs
+++ b/opossum/examples/ghost_focus.rs
@@ -4,11 +4,14 @@ use opossum::{
     degree,
     error::OpmResult,
     joule, millimeter,
-    nodes::{round_collimated_ray_source, Lens, NodeGroup, SpotDiagram, Wedge},
-    optic_node::{Alignable, OpticNode},
+    nodes::{
+        collimated_line_ray_source, round_collimated_ray_source, Lens, NodeGroup, SpotDiagram,
+        Wedge,
+    },
+    optic_node::{Alignable, OpticNode, LIDT},
     optic_ports::PortType,
     refractive_index::RefrIndexConst,
-    OpmDocument,
+    J_per_cm2, OpmDocument,
 };
 use std::path::Path;
 
@@ -16,7 +19,8 @@ fn main() -> OpmResult<()> {
     let mut scenery = NodeGroup::default();
     let i_src = scenery.add_node(
         // collimated_line_ray_source(millimeter!(50.), joule!(1.), 100)?
-        &round_collimated_ray_source(millimeter!(50.0), joule!(1.0), 7)?,
+        &round_collimated_ray_source(millimeter!(50.0), joule!(50.0), 15)?
+            .with_lidt(J_per_cm2!(20.)),
     )?;
     let i_sd = scenery.add_node(&SpotDiagram::default())?;
 
@@ -25,26 +29,31 @@ fn main() -> OpmResult<()> {
     lens.set_coating(&PortType::Output, "rear", &CoatingType::Fresnel)?;
     let i_l = scenery.add_node(&lens)?;
 
+    let mut lens2 = Lens::default();
+    lens2.set_coating(&PortType::Input, "front", &CoatingType::Fresnel)?;
+    lens2.set_coating(&PortType::Output, "rear", &CoatingType::Fresnel)?;
+    let i_l2 = scenery.add_node(&lens2)?;
+
     let mut wedge = Wedge::new(
         "wedge",
         millimeter!(20.0),
-        degree!(10.0),
+        degree!(0.5),
         &RefrIndexConst::new(1.5)?,
     )?
-    .with_tilt(degree!(5.0, 0.0, 0.0))?;
+    .with_tilt(degree!(0.5, 0.0, 0.0))?;
     wedge.set_coating(&PortType::Input, "front", &CoatingType::Fresnel)?;
     wedge.set_coating(&PortType::Output, "rear", &CoatingType::Fresnel)?;
     let i_w = scenery.add_node(&wedge)?;
 
     let i_sd2 = scenery.add_node(&SpotDiagram::default())?;
-    scenery.connect_nodes(i_src, "out1", i_sd, "in1", millimeter!(20.0))?;
-    scenery.connect_nodes(i_sd, "out1", i_l, "front", millimeter!(80.0))?;
-    scenery.connect_nodes(i_l, "rear", i_w, "front", millimeter!(70.0))?;
-    scenery.connect_nodes(i_w, "rear", i_sd2, "in1", millimeter!(70.0))?;
+    scenery.connect_nodes(i_src, "out1", i_l, "front", millimeter!(100.0))?;
+    scenery.connect_nodes(i_l, "rear", i_l2, "front", millimeter!(1000.0))?;
+    // scenery.connect_nodes(i_l2, "rear", i_w, "front", millimeter!(100.0))?;
+    // scenery.connect_nodes(i_w, "rear", i_sd, "in1", millimeter!(50.0))?;
 
     let mut doc = OpmDocument::new(scenery);
     let mut config = GhostFocusConfig::default();
-    config.set_max_bounces(1);
+    config.set_max_bounces(2);
     doc.add_analyzer(AnalyzerType::GhostFocus(config));
     // doc.add_analyzer(AnalyzerType::RayTrace(RayTraceConfig::default()));
     doc.save_to_file(Path::new("./opossum/playground/ghost_focus.opm"))
diff --git a/opossum/files_for_testing/opm/optic_ref.opm b/opossum/files_for_testing/opm/optic_ref.opm
index 0c78e263..514ecd6d 100644
--- a/opossum/files_for_testing/opm/optic_ref.opm
+++ b/opossum/files_for_testing/opm/optic_ref.opm
@@ -5,6 +5,7 @@ attributes:
   isometry: null
   name: test123
   uuid: 587ee70f-6f52-4420-89f6-e1618ff4dbdb
+  lidt: 10000.
   ports:
     inputs:
       front: 
diff --git a/opossum/files_for_testing/opm/opticscenery.opm b/opossum/files_for_testing/opm/opticscenery.opm
index 9bafe8e8..dcc8a3b5 100644
--- a/opossum/files_for_testing/opm/opticscenery.opm
+++ b/opossum/files_for_testing/opm/opticscenery.opm
@@ -6,6 +6,7 @@ scenery:
       inputs: {}
       outputs: {}
     uuid: b8cb049b-4eb9-4db8-8842-2fc7c70c27ba
+    lidt: 10000.
     props:
       expand view: !Bool false
       graph: !OpticGraph
@@ -15,6 +16,7 @@ scenery:
           attributes:
             name: dummy1
             uuid: 180328fe-7ad4-4568-b501-183b88c4daee
+            lidt: 10000.
             ports:
               inputs:
                 front:
@@ -31,6 +33,7 @@ scenery:
           attributes:
             name: dummy2
             uuid: 642ce76e-b071-43c0-a77e-1bdbb99b40d8
+            lidt: 10000.
             ports:
               inputs:
                 front:
diff --git a/opossum/src/analyzers/analyzable.rs b/opossum/src/analyzers/analyzable.rs
index b87f9747..0e3b596f 100644
--- a/opossum/src/analyzers/analyzable.rs
+++ b/opossum/src/analyzers/analyzable.rs
@@ -7,16 +7,13 @@ use crate::{
     error::{OpmResult, OpossumError},
     optic_node::OpticNode,
     optic_ports::PortType,
-    surface::Surface,
     utils::geom_transformation::Isometry,
 };
 use core::fmt::Debug;
 use std::fmt::Display;
 
 /// Marker trait for an optical node that can be analyzed
-pub trait Analyzable:
-    OpticNode + AnalysisEnergy + AnalysisRayTrace + AnalysisGhostFocus + Surface
-{
+pub trait Analyzable: OpticNode + AnalysisEnergy + AnalysisRayTrace + AnalysisGhostFocus {
     ///Sets the coating and isometry of this surface
     /// # Errors
     /// This function errors if the coating cannot be accessed
diff --git a/opossum/src/analyzers/ghostfocus.rs b/opossum/src/analyzers/ghostfocus.rs
index 8b5d76d8..59485bdc 100644
--- a/opossum/src/analyzers/ghostfocus.rs
+++ b/opossum/src/analyzers/ghostfocus.rs
@@ -380,13 +380,13 @@ impl GhostFocusHistory {
     pub fn rays_origin_report_str(&self, graph: &OpticGraph) -> String {
         let mut report_str = String::new();
         for (bounce, rays_correlation) in self.ray_node_correlation.iter().enumerate() {
-            if bounce == 0 {
-                report_str += "Origin at node '";
-            } else {
-                report_str += format!("bounce {bounce} at node '").as_str();
-            }
             for rays_origin in rays_correlation.values() {
                 if let Some(node_uuid) = rays_origin.node_origin {
+                    if bounce == 0 {
+                        report_str += "Origin at node '";
+                    } else {
+                        report_str += format!("bounce {bounce} at node '").as_str();
+                    }
                     if let Some(opt_ref) = graph.node_by_uuid(node_uuid) {
                         report_str +=
                             format!("{}', ", opt_ref.optical_ref.borrow().name()).as_str();
@@ -511,11 +511,11 @@ impl Plottable for GhostFocusHistory {
                 let plt_data = PlotData::MultiDim2 {
                     vec_of_xy_data: proj_pos_mm,
                 };
-
                 let series_label = format!("Bounce: {i}");
+
                 plt_series.push(PlotSeries::new(
                     &plt_data,
-                    RGBAColor(c.r, c.g, c.b, 1.),
+                    RGBAColor(c.r, c.g, c.b, 0.1),
                     Some(series_label),
                 ));
             }
diff --git a/opossum/src/analyzers/raytrace.rs b/opossum/src/analyzers/raytrace.rs
index 9935e508..8380711d 100644
--- a/opossum/src/analyzers/raytrace.rs
+++ b/opossum/src/analyzers/raytrace.rs
@@ -13,7 +13,6 @@ use crate::{
     rays::Rays,
     refractive_index::RefractiveIndexType,
     reporting::analysis_report::AnalysisReport,
-    surface::Surface,
     utils::geom_transformation::Isometry,
 };
 use log::info;
@@ -55,7 +54,7 @@ impl Analyzer for RayTracingAnalyzer {
     }
 }
 /// Trait for implementing the ray trace analysis.
-pub trait AnalysisRayTrace: OpticNode + Surface {
+pub trait AnalysisRayTrace: OpticNode {
     /// Perform a ray trace analysis an [`OpticNode`].
     ///
     /// # Errors
diff --git a/opossum/src/nodes/beam_splitter/mod.rs b/opossum/src/nodes/beam_splitter/mod.rs
index 736be84b..cc331698 100644
--- a/opossum/src/nodes/beam_splitter/mod.rs
+++ b/opossum/src/nodes/beam_splitter/mod.rs
@@ -15,7 +15,7 @@ use crate::{
     ray::SplittingConfig,
     rays::Rays,
     spectrum::{merge_spectra, Spectrum},
-    surface::{OpticalSurface, Plane, Surface},
+    surface::{OpticalSurface, Plane},
     utils::EnumProxy,
 };
 
@@ -294,6 +294,10 @@ impl OpticNode for BeamSplitter {
     fn node_attr_mut(&mut self) -> &mut NodeAttr {
         &mut self.node_attr
     }
+
+    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
+        todo!()
+    }
 }
 
 impl Dottable for BeamSplitter {
@@ -301,11 +305,7 @@ impl Dottable for BeamSplitter {
         "lightpink"
     }
 }
-impl Surface for BeamSplitter {
-    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
-        todo!()
-    }
-}
+
 impl Analyzable for BeamSplitter {}
 impl AnalysisGhostFocus for BeamSplitter {}
 
diff --git a/opossum/src/nodes/cylindric_lens/analysis_ghostfocus.rs b/opossum/src/nodes/cylindric_lens/analysis_ghostfocus.rs
index 2749990c..832b1350 100644
--- a/opossum/src/nodes/cylindric_lens/analysis_ghostfocus.rs
+++ b/opossum/src/nodes/cylindric_lens/analysis_ghostfocus.rs
@@ -43,10 +43,9 @@ impl AnalysisGhostFocus for CylindricLens {
             )?;
         };
 
-        let Some(incoming_rays) = incoming_data.get(in_port) else {
-            return Ok(LightRays::default());
-        };
-        let mut rays_bundle = incoming_rays.clone();
+        let mut rays_bundle = incoming_data
+            .get(in_port)
+            .map_or_else(Vec::<Rays>::new, std::clone::Clone::clone);
 
         self.enter_through_surface(
             &mut rays_bundle,
diff --git a/opossum/src/nodes/cylindric_lens/mod.rs b/opossum/src/nodes/cylindric_lens/mod.rs
index 1d96efa4..4df97a51 100644
--- a/opossum/src/nodes/cylindric_lens/mod.rs
+++ b/opossum/src/nodes/cylindric_lens/mod.rs
@@ -8,12 +8,12 @@ use crate::{
     dottable::Dottable,
     error::{OpmResult, OpossumError},
     millimeter,
-    optic_node::{Alignable, OpticNode},
+    optic_node::{Alignable, OpticNode, LIDT},
     optic_ports::{OpticPorts, PortType},
     properties::Proptype,
     rays::Rays,
     refractive_index::{RefrIndexConst, RefractiveIndex, RefractiveIndexType},
-    surface::{hit_map::HitMap, Cylinder, OpticalSurface, Plane, Surface},
+    surface::{hit_map::HitMap, Cylinder, OpticalSurface, Plane},
     utils::{geom_transformation::Isometry, EnumProxy},
 };
 #[cfg(feature = "bevy")]
@@ -157,6 +157,9 @@ impl CylindricLens {
         lens.update_surfaces()?;
         Ok(lens)
     }
+}
+
+impl OpticNode for CylindricLens {
     fn update_surfaces(&mut self) -> OpmResult<()> {
         let Ok(Proptype::Length(front_roc)) = self.node_attr.get_property("front curvature") else {
             return Err(OpossumError::Analysis("cannot read front curvature".into()));
@@ -176,9 +179,6 @@ impl CylindricLens {
         };
         Ok(())
     }
-}
-
-impl OpticNode for CylindricLens {
     fn reset_data(&mut self) {
         self.front_surf.set_backwards_rays_cache(Vec::<Rays>::new());
         self.front_surf.set_forward_rays_cache(Vec::<Rays>::new());
@@ -201,8 +201,12 @@ impl OpticNode for CylindricLens {
     fn node_attr_mut(&mut self) -> &mut NodeAttr {
         &mut self.node_attr
     }
-    fn after_deserialization_hook(&mut self) -> OpmResult<()> {
-        self.update_surfaces()
+    fn get_surface_mut(&mut self, surf_name: &str) -> &mut OpticalSurface {
+        if surf_name == "front" {
+            &mut self.front_surf
+        } else {
+            &mut self.rear_surf
+        }
     }
 }
 
@@ -213,15 +217,8 @@ impl Dottable for CylindricLens {
         "aqua"
     }
 }
-impl Surface for CylindricLens {
-    fn get_surface_mut(&mut self, surf_name: &str) -> &mut OpticalSurface {
-        if surf_name == "front" {
-            &mut self.front_surf
-        } else {
-            &mut self.rear_surf
-        }
-    }
-}
+
+impl LIDT for CylindricLens {}
 impl Analyzable for CylindricLens {}
 
 #[cfg(test)]
diff --git a/opossum/src/nodes/detector.rs b/opossum/src/nodes/detector.rs
index 5a3a2123..fdedd159 100644
--- a/opossum/src/nodes/detector.rs
+++ b/opossum/src/nodes/detector.rs
@@ -9,9 +9,9 @@ use crate::{
     error::{OpmResult, OpossumError},
     light_result::LightResult,
     lightdata::LightData,
-    optic_node::OpticNode,
+    optic_node::{OpticNode, LIDT},
     optic_ports::{OpticPorts, PortType},
-    surface::{OpticalSurface, Plane, Surface},
+    surface::{OpticalSurface, Plane},
     utils::geom_transformation::Isometry,
 };
 use log::warn;
@@ -82,6 +82,9 @@ impl OpticNode for Detector {
         self.light_data = None;
         self.surface.reset_hit_map();
     }
+    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
+        &mut self.surface
+    }
 }
 
 impl Debug for Detector {
@@ -97,6 +100,8 @@ impl Dottable for Detector {
         "lemonchiffon"
     }
 }
+impl LIDT for Detector {}
+
 impl Analyzable for Detector {}
 impl AnalysisGhostFocus for Detector {}
 impl AnalysisEnergy for Detector {
@@ -170,11 +175,6 @@ impl AnalysisRayTrace for Detector {
     }
 }
 
-impl Surface for Detector {
-    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
-        todo!()
-    }
-}
 #[cfg(test)]
 mod test {
     use super::*;
diff --git a/opossum/src/nodes/dummy.rs b/opossum/src/nodes/dummy.rs
index 1ad3ee5c..47e97128 100644
--- a/opossum/src/nodes/dummy.rs
+++ b/opossum/src/nodes/dummy.rs
@@ -9,9 +9,9 @@ use crate::{
     error::{OpmResult, OpossumError},
     light_result::LightResult,
     lightdata::LightData,
-    optic_node::OpticNode,
+    optic_node::{OpticNode, LIDT},
     optic_ports::{OpticPorts, PortType},
-    surface::{OpticalSurface, Plane, Surface},
+    surface::{OpticalSurface, Plane},
     utils::geom_transformation::Isometry,
 };
 
@@ -64,6 +64,8 @@ impl Dummy {
         dummy
     }
 }
+impl LIDT for Dummy {}
+
 impl Analyzable for Dummy {}
 impl AnalysisGhostFocus for Dummy {}
 impl AnalysisEnergy for Dummy {
@@ -79,11 +81,7 @@ impl AnalysisEnergy for Dummy {
         )
     }
 }
-impl Surface for Dummy {
-    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
-        todo!()
-    }
-}
+
 impl AnalysisRayTrace for Dummy {
     fn analyze(
         &mut self,
@@ -140,6 +138,9 @@ impl OpticNode for Dummy {
     fn reset_data(&mut self) {
         self.surface.reset_hit_map();
     }
+    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
+        &mut self.surface
+    }
 }
 
 impl Dottable for Dummy {}
diff --git a/opossum/src/nodes/energy_meter.rs b/opossum/src/nodes/energy_meter.rs
index 13df2d6d..43235726 100644
--- a/opossum/src/nodes/energy_meter.rs
+++ b/opossum/src/nodes/energy_meter.rs
@@ -9,11 +9,11 @@ use crate::{
     joule,
     light_result::LightResult,
     lightdata::LightData,
-    optic_node::OpticNode,
+    optic_node::{OpticNode, LIDT},
     optic_ports::{OpticPorts, PortType},
     properties::{Properties, Proptype},
     reporting::node_report::NodeReport,
-    surface::{OpticalSurface, Plane, Surface},
+    surface::{OpticalSurface, Plane},
     utils::geom_transformation::Isometry,
 };
 use log::warn;
@@ -196,12 +196,11 @@ impl OpticNode for EnergyMeter {
         self.light_data = None;
         self.surface.reset_hit_map();
     }
-}
-impl Surface for EnergyMeter {
     fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
-        todo!()
+        &mut self.surface
     }
 }
+
 impl Debug for EnergyMeter {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match &self.light_data {
@@ -215,6 +214,7 @@ impl Dottable for EnergyMeter {
         "whitesmoke"
     }
 }
+impl LIDT for EnergyMeter {}
 impl Analyzable for EnergyMeter {}
 impl AnalysisGhostFocus for EnergyMeter {}
 impl AnalysisEnergy for EnergyMeter {
diff --git a/opossum/src/nodes/fluence_detector.rs b/opossum/src/nodes/fluence_detector.rs
index 40487103..c4f9a412 100644
--- a/opossum/src/nodes/fluence_detector.rs
+++ b/opossum/src/nodes/fluence_detector.rs
@@ -16,13 +16,13 @@ use crate::{
     error::{OpmResult, OpossumError},
     light_result::{LightRays, LightResult},
     lightdata::LightData,
-    optic_node::OpticNode,
+    optic_node::{OpticNode, LIDT},
     optic_ports::{OpticPorts, PortType},
     plottable::{PlotArgs, PlotData, PlotParameters, PlotSeries, PlotType, Plottable},
     properties::{Properties, Proptype},
     rays::Rays,
     reporting::node_report::NodeReport,
-    surface::{OpticalSurface, Plane, Surface},
+    surface::{OpticalSurface, Plane},
     utils::geom_transformation::Isometry,
 };
 
@@ -78,36 +78,11 @@ impl FluenceDetector {
         fld
     }
 }
-impl Surface for FluenceDetector {
+
+impl OpticNode for FluenceDetector {
     fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
-        todo!()
+        &mut self.surface
     }
-}
-impl OpticNode for FluenceDetector {
-    // fn export_data(&self, report_dir: &Path, uuid: &str) -> OpmResult<()> {
-    //     self.light_data.as_ref().map_or_else(
-    //         || {
-    //             Err(OpossumError::Other(
-    //                 "Fluence detector: no light data for export available".into(),
-    //             ))
-    //         },
-    //         |rays| {
-    //             let file_path = PathBuf::from(report_dir).join(Path::new(&format!(
-    //                 "fluence_{}_{}.png",
-    //                 self.name(),
-    //                 uuid
-    //             )));
-    //             let _ = rays.calc_fluence_at_position().map_or_else(
-    //                 |_| {
-    //                     warn!("Fluence Detector diagram: no fluence data for export available",);
-    //                     Ok(None)
-    //                 },
-    //                 |fluence_data| fluence_data.to_plot(&file_path, PltBackEnd::Bitmap),
-    //             );
-    //             Ok(())
-    //         },
-    //     )
-    // }
     fn node_report(&self, uuid: &str) -> Option<NodeReport> {
         let mut props = Properties::default();
         let data = &self.light_data;
@@ -152,12 +127,6 @@ impl OpticNode for FluenceDetector {
                 }
             }
         }
-        // else if let Some(LightData::GhostFocus(v_rays)) = data{
-        //     todo!()
-        // }
-        // else{
-        //     todo!()
-        // }
         Some(NodeReport::new(
             &self.node_type(),
             &self.name(),
@@ -182,6 +151,7 @@ impl Dottable for FluenceDetector {
         "hotpink"
     }
 }
+impl LIDT for FluenceDetector {}
 impl Analyzable for FluenceDetector {}
 impl AnalysisGhostFocus for FluenceDetector {
     fn analyze(
diff --git a/opossum/src/nodes/ideal_filter.rs b/opossum/src/nodes/ideal_filter.rs
index e4a598f8..f6569b41 100644
--- a/opossum/src/nodes/ideal_filter.rs
+++ b/opossum/src/nodes/ideal_filter.rs
@@ -9,11 +9,11 @@ use crate::{
     error::{OpmResult, OpossumError},
     light_result::LightResult,
     lightdata::LightData,
-    optic_node::OpticNode,
+    optic_node::{OpticNode, LIDT},
     optic_ports::{OpticPorts, PortType},
     properties::Proptype,
     spectrum::Spectrum,
-    surface::{OpticalSurface, Plane, Surface},
+    surface::{OpticalSurface, Plane},
     utils::{geom_transformation::Isometry, EnumProxy},
 };
 use serde::{Deserialize, Serialize};
@@ -181,6 +181,9 @@ impl OpticNode for IdealFilter {
     fn reset_data(&mut self) {
         self.surface.reset_hit_map();
     }
+    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
+        &mut self.surface
+    }
 }
 
 impl Dottable for IdealFilter {
@@ -188,6 +191,7 @@ impl Dottable for IdealFilter {
         "darkgray"
     }
 }
+impl LIDT for IdealFilter {}
 impl Analyzable for IdealFilter {}
 impl AnalysisGhostFocus for IdealFilter {}
 impl AnalysisEnergy for IdealFilter {
@@ -209,11 +213,6 @@ impl AnalysisEnergy for IdealFilter {
         }
     }
 }
-impl Surface for IdealFilter {
-    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
-        todo!()
-    }
-}
 impl AnalysisRayTrace for IdealFilter {
     fn analyze(
         &mut self,
diff --git a/opossum/src/nodes/lens/analysis_ghostfocus.rs b/opossum/src/nodes/lens/analysis_ghostfocus.rs
index 357c4ba8..b4afd3f6 100644
--- a/opossum/src/nodes/lens/analysis_ghostfocus.rs
+++ b/opossum/src/nodes/lens/analysis_ghostfocus.rs
@@ -24,9 +24,10 @@ impl AnalysisGhostFocus for Lens {
             self.get_node_attributes_ray_trace(&self.node_attr)?;
         let in_port = &self.ports().names(&PortType::Input)[0];
         let out_port = &self.ports().names(&PortType::Output)[0];
-        let Some(incoming_rays) = incoming_data.get(in_port) else {
-            return Ok(LightRays::default());
-        };
+        let mut rays_bundle = incoming_data
+            .get(in_port)
+            .map_or_else(Vec::<Rays>::new, std::clone::Clone::clone);
+
         let thickness_iso: Isometry = Isometry::new_along_z(center_thickness)?;
 
         if self.inverted() {
@@ -45,7 +46,6 @@ impl AnalysisGhostFocus for Lens {
             )?;
         };
 
-        let mut rays_bundle = incoming_rays.clone();
         self.enter_through_surface(
             &mut rays_bundle,
             &AnalyzerType::GhostFocus(config.clone()),
diff --git a/opossum/src/nodes/lens/mod.rs b/opossum/src/nodes/lens/mod.rs
index 053d75ed..d321dd7a 100644
--- a/opossum/src/nodes/lens/mod.rs
+++ b/opossum/src/nodes/lens/mod.rs
@@ -8,12 +8,12 @@ use crate::{
     dottable::Dottable,
     error::{OpmResult, OpossumError},
     millimeter,
-    optic_node::{Alignable, OpticNode},
+    optic_node::{Alignable, OpticNode, LIDT},
     optic_ports::{OpticPorts, PortType},
     properties::Proptype,
     rays::Rays,
     refractive_index::{RefrIndexConst, RefractiveIndex, RefractiveIndexType},
-    surface::{hit_map::HitMap, OpticalSurface, Plane, Sphere, Surface},
+    surface::{hit_map::HitMap, OpticalSurface, Plane, Sphere},
     utils::{geom_transformation::Isometry, EnumProxy},
 };
 #[cfg(feature = "bevy")]
@@ -157,25 +157,7 @@ impl Lens {
         lens.update_surfaces()?;
         Ok(lens)
     }
-    fn update_surfaces(&mut self) -> OpmResult<()> {
-        let Ok(Proptype::Length(front_roc)) = self.node_attr.get_property("front curvature") else {
-            return Err(OpossumError::Analysis("cannot read front curvature".into()));
-        };
-        self.front_surf = if front_roc.is_infinite() {
-            OpticalSurface::new(Box::new(Plane::new(&Isometry::identity())))
-        } else {
-            OpticalSurface::new(Box::new(Sphere::new(*front_roc, &Isometry::identity())?))
-        };
-        let Ok(Proptype::Length(rear_roc)) = self.node_attr.get_property("rear curvature") else {
-            return Err(OpossumError::Analysis("cannot read rear curvature".into()));
-        };
-        self.rear_surf = if rear_roc.is_infinite() {
-            OpticalSurface::new(Box::new(Plane::new(&Isometry::identity())))
-        } else {
-            OpticalSurface::new(Box::new(Sphere::new(*rear_roc, &Isometry::identity())?))
-        };
-        Ok(())
-    }
+
     /// create a default aperture: defined by
     ///  - intersection of two spheres
     ///  - intersection of sphere and plane
@@ -264,17 +246,26 @@ impl Lens {
     }
 }
 
-impl Surface for Lens {
-    fn get_surface_mut(&mut self, surf_name: &str) -> &mut OpticalSurface {
-        if surf_name == "front" {
-            &mut self.front_surf
+impl OpticNode for Lens {
+    fn update_surfaces(&mut self) -> OpmResult<()> {
+        let Ok(Proptype::Length(front_roc)) = self.node_attr.get_property("front curvature") else {
+            return Err(OpossumError::Analysis("cannot read front curvature".into()));
+        };
+        self.front_surf = if front_roc.is_infinite() {
+            OpticalSurface::new(Box::new(Plane::new(&Isometry::identity())))
         } else {
-            &mut self.rear_surf
-        }
+            OpticalSurface::new(Box::new(Sphere::new(*front_roc, &Isometry::identity())?))
+        };
+        let Ok(Proptype::Length(rear_roc)) = self.node_attr.get_property("rear curvature") else {
+            return Err(OpossumError::Analysis("cannot read rear curvature".into()));
+        };
+        self.rear_surf = if rear_roc.is_infinite() {
+            OpticalSurface::new(Box::new(Plane::new(&Isometry::identity())))
+        } else {
+            OpticalSurface::new(Box::new(Sphere::new(*rear_roc, &Isometry::identity())?))
+        };
+        Ok(())
     }
-}
-
-impl OpticNode for Lens {
     fn reset_data(&mut self) {
         self.front_surf.set_backwards_rays_cache(Vec::<Rays>::new());
         self.front_surf.set_forward_rays_cache(Vec::<Rays>::new());
@@ -296,8 +287,12 @@ impl OpticNode for Lens {
     fn node_attr_mut(&mut self) -> &mut NodeAttr {
         &mut self.node_attr
     }
-    fn after_deserialization_hook(&mut self) -> OpmResult<()> {
-        self.update_surfaces()
+    fn get_surface_mut(&mut self, surf_name: &str) -> &mut OpticalSurface {
+        if surf_name == "front" {
+            &mut self.front_surf
+        } else {
+            &mut self.rear_surf
+        }
     }
 }
 // impl SDF for Lens
@@ -310,6 +305,7 @@ impl OpticNode for Lens {
 // }
 impl Alignable for Lens {}
 impl Analyzable for Lens {}
+impl LIDT for Lens {}
 
 impl Dottable for Lens {
     fn node_color(&self) -> &str {
diff --git a/opossum/src/nodes/node_attr.rs b/opossum/src/nodes/node_attr.rs
index 9c6eeef0..05ee8927 100644
--- a/opossum/src/nodes/node_attr.rs
+++ b/opossum/src/nodes/node_attr.rs
@@ -14,8 +14,11 @@ use crate::{
     optic_senery_rsc::SceneryResources,
     properties::{PropCondition, Properties, Proptype},
     utils::geom_transformation::Isometry,
+    J_per_cm2,
 };
 
+use super::fluence_detector::Fluence;
+
 /// Struct for sotring common attributes of optical nodes.
 #[derive(Debug, Clone, Serialize, Deserialize)]
 pub struct NodeAttr {
@@ -24,6 +27,7 @@ pub struct NodeAttr {
     name: String,
     ports: OpticPorts,
     uuid: Uuid,
+    lidt: Fluence,
     #[serde(default)]
     props: Properties,
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -71,6 +75,7 @@ impl NodeAttr {
             alignment: None,
             align_like_node_at_distance: None,
             uuid: Uuid::new_v4(),
+            lidt: J_per_cm2!(1.),
         }
     }
     /// Returns the name property of this node.
@@ -211,6 +216,16 @@ impl NodeAttr {
         self.uuid = *uuid;
     }
 
+    /// Returns a reference to the lidt of this [`NodeAttr`].
+    #[must_use]
+    pub const fn lidt(&self) -> &Fluence {
+        &self.lidt
+    }
+    ///Sets the lidt of this [`NodeAttr`].
+    pub fn set_lidt(&mut self, lidt: &Fluence) {
+        self.lidt = *lidt;
+    }
+
     /// set the nodeindex and distance of the node to which this node should be aligned to
     pub fn set_align_like_node_at_distance(&mut self, node_idx: NodeIndex, distance: Length) {
         self.align_like_node_at_distance = Some((node_idx, distance));
diff --git a/opossum/src/nodes/node_group/mod.rs b/opossum/src/nodes/node_group/mod.rs
index 2efdc2c1..7432ac8b 100644
--- a/opossum/src/nodes/node_group/mod.rs
+++ b/opossum/src/nodes/node_group/mod.rs
@@ -16,7 +16,7 @@ use crate::{
     properties::{Properties, Proptype},
     rays::Rays,
     reporting::{analysis_report::AnalysisReport, node_report::NodeReport},
-    surface::{OpticalSurface, Surface},
+    surface::OpticalSurface,
     utils::EnumProxy,
     SceneryResources,
 };
@@ -507,9 +507,6 @@ impl OpticNode for NodeGroup {
         }
         self.accumulated_rays = Vec::<HashMap<Uuid, Rays>>::new();
     }
-}
-
-impl Surface for NodeGroup {
     fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
         todo!()
     }
diff --git a/opossum/src/nodes/paraxial_surface.rs b/opossum/src/nodes/paraxial_surface.rs
index 4b3287d4..27468084 100644
--- a/opossum/src/nodes/paraxial_surface.rs
+++ b/opossum/src/nodes/paraxial_surface.rs
@@ -10,10 +10,11 @@ use crate::{
     light_result::LightResult,
     lightdata::LightData,
     millimeter,
-    optic_node::{Alignable, OpticNode},
+    optic_node::{Alignable, OpticNode, LIDT},
     optic_ports::{OpticPorts, PortType},
     properties::Proptype,
-    surface::{OpticalSurface, Plane, Surface},
+    surface::{OpticalSurface, Plane},
+    utils::geom_transformation::Isometry,
 };
 use uom::{num_traits::Zero, si::f64::Length};
 
@@ -42,6 +43,7 @@ use super::node_attr::NodeAttr;
 #[derive(Debug, Clone)]
 pub struct ParaxialSurface {
     node_attr: NodeAttr,
+    surface: OpticalSurface,
 }
 impl Default for ParaxialSurface {
     /// Create a default paraxial surface (ideal thin lens) with a focal length of 10 mm.
@@ -61,7 +63,10 @@ impl Default for ParaxialSurface {
                 millimeter!(10.0).into(),
             )
             .unwrap();
-        Self { node_attr }
+        Self {
+            node_attr,
+            surface: OpticalSurface::new(Box::new(Plane::new(&Isometry::identity()))),
+        }
     }
 }
 impl ParaxialSurface {
@@ -94,6 +99,9 @@ impl OpticNode for ParaxialSurface {
     fn node_attr_mut(&mut self) -> &mut NodeAttr {
         &mut self.node_attr
     }
+    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
+        &mut self.surface
+    }
 }
 
 impl Alignable for ParaxialSurface {}
@@ -103,6 +111,7 @@ impl Dottable for ParaxialSurface {
         "palegreen"
     }
 }
+impl LIDT for ParaxialSurface {}
 impl Analyzable for ParaxialSurface {}
 impl AnalysisGhostFocus for ParaxialSurface {}
 impl AnalysisEnergy for ParaxialSurface {
@@ -118,61 +127,55 @@ impl AnalysisEnergy for ParaxialSurface {
         Ok(LightResult::from([(outport.into(), data.clone())]))
     }
 }
-impl Surface for ParaxialSurface {
-    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
-        todo!()
-    }
-}
 impl AnalysisRayTrace for ParaxialSurface {
     fn analyze(
         &mut self,
         incoming_data: LightResult,
         config: &RayTraceConfig,
     ) -> OpmResult<LightResult> {
-        let (in_port, out_port) = if self.inverted() {
-            ("rear", "front")
-        } else {
-            ("front", "rear")
-        };
+        let in_port = &self.ports().names(&PortType::Input)[0];
+        let out_port = &self.ports().names(&PortType::Output)[0];
+
         let Some(data) = incoming_data.get(in_port) else {
             return Ok(LightResult::default());
         };
-        if let LightData::Geometric(mut rays) = data.clone() {
-            let Ok(Proptype::Length(focal_length)) = self.node_attr.get_property("focal length")
-            else {
-                return Err(OpossumError::Analysis("cannot read focal length".into()));
-            };
-            if let Some(iso) = self.effective_iso() {
-                rays.refract_on_surface(
-                    &mut OpticalSurface::new(Box::new(Plane::new(&iso))),
-                    None,
-                )?;
-                rays.refract_paraxial(*focal_length, &iso)?;
-            } else {
-                return Err(OpossumError::Analysis(
-                    "no location for surface defined. Aborting".into(),
-                ));
-            }
-            if let Some(aperture) = self.ports().aperture(&PortType::Input, in_port) {
-                rays.apodize(aperture)?;
-                rays.invalidate_by_threshold_energy(config.min_energy_per_ray())?;
-            } else {
-                return Err(OpossumError::OpticPort("input aperture not found".into()));
-            };
-            if let Some(aperture) = self.ports().aperture(&PortType::Output, out_port) {
-                rays.apodize(aperture)?;
-                rays.invalidate_by_threshold_energy(config.min_energy_per_ray())?;
-            } else {
-                return Err(OpossumError::OpticPort("output aperture not found".into()));
-            };
-            let mut light_result = LightResult::default();
-            light_result.insert(out_port.into(), LightData::Geometric(rays));
-            Ok(light_result)
+        let LightData::Geometric(mut rays) = data.clone() else {
+            return Err(OpossumError::Analysis(
+                "expected ray data at input port".into(),
+            ));
+        };
+
+        let Proptype::Length(focal_length) = self.node_attr.get_property("focal length")?.clone()
+        else {
+            return Err(OpossumError::Analysis("cannot read focal length".into()));
+        };
+        let Some(eff_iso) = self.effective_iso() else {
+            return Err(OpossumError::Analysis(
+                "no location for surface defined. Aborting".into(),
+            ));
+        };
+
+        if let Some(aperture) = self.ports().aperture(&PortType::Input, in_port) {
+            rays.apodize(aperture)?;
+            rays.invalidate_by_threshold_energy(config.min_energy_per_ray())?;
         } else {
-            Err(crate::error::OpossumError::Analysis(
-                "No LightData::Geometric for analyzer type RayTrace".into(),
-            ))
-        }
+            return Err(OpossumError::OpticPort("input aperture not found".into()));
+        };
+        let surf = self.get_surface_mut("");
+        surf.set_isometry(&eff_iso);
+
+        rays.refract_on_surface(surf, None)?;
+        rays.refract_paraxial(focal_length, &eff_iso)?;
+
+        if let Some(aperture) = self.ports().aperture(&PortType::Output, out_port) {
+            rays.apodize(aperture)?;
+            rays.invalidate_by_threshold_energy(config.min_energy_per_ray())?;
+        } else {
+            return Err(OpossumError::OpticPort("output aperture not found".into()));
+        };
+        let mut light_result = LightResult::default();
+        light_result.insert(out_port.into(), LightData::Geometric(rays));
+        Ok(light_result)
     }
 }
 
diff --git a/opossum/src/nodes/ray_propagation_visualizer.rs b/opossum/src/nodes/ray_propagation_visualizer.rs
index cef8299d..1f9c59f0 100644
--- a/opossum/src/nodes/ray_propagation_visualizer.rs
+++ b/opossum/src/nodes/ray_propagation_visualizer.rs
@@ -20,13 +20,13 @@ use crate::{
     light_result::{LightRays, LightResult},
     lightdata::LightData,
     millimeter,
-    optic_node::OpticNode,
+    optic_node::{OpticNode, LIDT},
     optic_ports::{OpticPorts, PortType},
     plottable::{PlotArgs, PlotData, PlotParameters, PlotSeries, PlotType, Plottable},
     properties::{Properties, Proptype},
     rays::Rays,
     reporting::node_report::NodeReport,
-    surface::{OpticalSurface, Plane, Surface},
+    surface::{OpticalSurface, Plane},
     utils::geom_transformation::Isometry,
 };
 /// A ray-propagation monitor
@@ -92,11 +92,7 @@ impl RayPropagationVisualizer {
         Ok(rpv)
     }
 }
-impl Surface for RayPropagationVisualizer {
-    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
-        todo!()
-    }
-}
+
 impl OpticNode for RayPropagationVisualizer {
     fn node_report(&self, uuid: &str) -> Option<NodeReport> {
         let mut props = Properties::default();
@@ -144,6 +140,9 @@ impl OpticNode for RayPropagationVisualizer {
         self.light_data = None;
         self.surface.reset_hit_map();
     }
+    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
+        &mut self.surface
+    }
 }
 
 impl Dottable for RayPropagationVisualizer {
@@ -151,6 +150,7 @@ impl Dottable for RayPropagationVisualizer {
         "darkgreen"
     }
 }
+impl LIDT for RayPropagationVisualizer {}
 impl Analyzable for RayPropagationVisualizer {}
 impl AnalysisGhostFocus for RayPropagationVisualizer {
     fn analyze(
diff --git a/opossum/src/nodes/reference.rs b/opossum/src/nodes/reference.rs
index 5a7b8613..8165eb59 100644
--- a/opossum/src/nodes/reference.rs
+++ b/opossum/src/nodes/reference.rs
@@ -12,10 +12,10 @@ use crate::{
     dottable::Dottable,
     error::{OpmResult, OpossumError},
     light_result::LightResult,
-    optic_node::OpticNode,
+    optic_node::{OpticNode, LIDT},
     optic_ports::OpticPorts,
     optic_ref::OpticRef,
-    surface::{OpticalSurface, Surface},
+    surface::OpticalSurface,
     utils::geom_transformation::Isometry,
 };
 
@@ -119,6 +119,14 @@ impl OpticNode for NodeReference {
         // setting an isometry is silently ignored. Isometry is defined by the refrenced node.
         // self.node_attr.set_isometry(isometry);
     }
+    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
+        todo!()
+        // self.reference.as_ref().and_then(|rf| {
+        //     let ref_node = rf.upgrade().unwrap();
+        //     let node = ref_node.borrow();
+        //     node.get_surface_mut()
+        // })
+    }
 }
 
 impl Dottable for NodeReference {
@@ -126,11 +134,8 @@ impl Dottable for NodeReference {
         "lightsalmon3"
     }
 }
-impl Surface for NodeReference {
-    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
-        todo!()
-    }
-}
+
+impl LIDT for NodeReference {}
 impl Analyzable for NodeReference {}
 impl AnalysisGhostFocus for NodeReference {}
 impl AnalysisEnergy for NodeReference {
diff --git a/opossum/src/nodes/reflective_grating.rs b/opossum/src/nodes/reflective_grating.rs
index 4579db76..73e1f1c5 100644
--- a/opossum/src/nodes/reflective_grating.rs
+++ b/opossum/src/nodes/reflective_grating.rs
@@ -13,12 +13,13 @@ use crate::{
     light_result::LightResult,
     lightdata::LightData,
     num_per_mm,
-    optic_node::{Alignable, OpticNode},
+    optic_node::{Alignable, OpticNode, LIDT},
     optic_ports::{OpticPorts, PortType},
     properties::Proptype,
     radian,
     refractive_index::refr_index_vaccuum,
-    surface::{OpticalSurface, Plane, Surface},
+    surface::{OpticalSurface, Plane},
+    utils::geom_transformation::Isometry,
 };
 use approx::relative_eq;
 use nalgebra::Vector3;
@@ -48,6 +49,7 @@ pub type LinearDensity = uom::si::f64::LinearNumberDensity;
 ///   - `line density`
 pub struct ReflectiveGrating {
     node_attr: NodeAttr,
+    surface: OpticalSurface,
 }
 impl Default for ReflectiveGrating {
     /// Create a reflective grating with a specified line density.
@@ -73,7 +75,10 @@ impl Default for ReflectiveGrating {
         ports.add(&PortType::Input, "input").unwrap();
         ports.add(&PortType::Output, "diffracted").unwrap();
         node_attr.set_ports(ports);
-        Self { node_attr }
+        Self {
+            node_attr,
+            surface: OpticalSurface::new(Box::new(Plane::new(&Isometry::identity()))),
+        }
     }
 }
 
@@ -161,11 +166,7 @@ impl Dottable for ReflectiveGrating {
         "cornsilk"
     }
 }
-impl Surface for ReflectiveGrating {
-    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
-        todo!()
-    }
-}
+impl LIDT for ReflectiveGrating {}
 impl Analyzable for ReflectiveGrating {}
 impl AnalysisGhostFocus for ReflectiveGrating {}
 impl AnalysisEnergy for ReflectiveGrating {
@@ -196,27 +197,29 @@ impl AnalysisRayTrace for ReflectiveGrating {
             return Ok(LightResult::default());
         };
         if let LightData::Geometric(mut rays) = data.clone() {
-            let Ok(Proptype::I32(diffraction_order)) =
-                self.node_attr.get_property("diffraction order")
+            let Proptype::I32(diffraction_order) =
+                self.node_attr.get_property("diffraction order")?.clone()
             else {
                 return Err(OpossumError::Analysis(
                     "cannot read diffraction order".into(),
                 ));
             };
-            let Ok(Proptype::LinearDensity(line_density)) =
-                self.node_attr.get_property("line density")
+            let Proptype::LinearDensity(line_density) =
+                self.node_attr.get_property("line density")?.clone()
             else {
                 return Err(OpossumError::Analysis("cannot read line density".into()));
             };
 
             let diffracted = if let Some(iso) = self.effective_iso() {
+                let surf = self.get_surface_mut(inport);
+                surf.set_isometry(&iso);
                 let grating_vector =
                     2. * PI * line_density.value * iso.transform_vector_f64(&Vector3::x());
                 let mut diffracted_rays = rays.diffract_on_periodic_surface(
-                    &Plane::new(&iso),
+                    surf,
                     &refr_index_vaccuum(),
                     grating_vector,
-                    diffraction_order,
+                    &diffraction_order,
                 )?;
 
                 if let Some(aperture) = self.ports().aperture(&PortType::Input, inport) {
@@ -249,6 +252,9 @@ impl OpticNode for ReflectiveGrating {
     fn node_attr_mut(&mut self) -> &mut NodeAttr {
         &mut self.node_attr
     }
+    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
+        &mut self.surface
+    }
 }
 
 #[cfg(test)]
diff --git a/opossum/src/nodes/source.rs b/opossum/src/nodes/source.rs
index af85f8da..91f4a73d 100644
--- a/opossum/src/nodes/source.rs
+++ b/opossum/src/nodes/source.rs
@@ -14,12 +14,12 @@ use crate::{
     light_result::{LightRays, LightResult},
     lightdata::LightData,
     millimeter,
-    optic_node::{Alignable, OpticNode},
+    optic_node::{Alignable, OpticNode, LIDT},
     optic_ports::{OpticPorts, PortType},
     properties::Proptype,
     ray::Ray,
     rays::Rays,
-    surface::{hit_map::HitMap, OpticalSurface, Plane, Surface},
+    surface::{hit_map::HitMap, OpticalSurface, Plane},
     utils::{geom_transformation::Isometry, EnumProxy},
 };
 use std::{collections::HashMap, fmt::Debug};
@@ -171,6 +171,9 @@ impl OpticNode for Source {
         maps.insert("out1".to_string(), self.surface.hit_map().to_owned());
         maps
     }
+    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
+        &mut self.surface
+    }
 }
 
 impl Dottable for Source {
@@ -178,6 +181,7 @@ impl Dottable for Source {
         "slateblue"
     }
 }
+impl LIDT for Source {}
 impl Analyzable for Source {}
 impl AnalysisEnergy for Source {
     fn analyze(&mut self, _incoming_data: LightResult) -> OpmResult<LightResult> {
@@ -310,23 +314,10 @@ impl AnalysisGhostFocus for Source {
                 "no location for surface defined. Aborting".into(),
             ));
         }
-        // let outgoing = AnalysisRayTrace::analyze(
-        //     self,
-        //     light_rays_to_light_result(incoming_data),
-        //     &RayTraceConfig::default(),
-        // )?;
+
         let mut out_light_rays = LightRays::default();
         out_light_rays.insert("out1".into(), rays);
         Ok(out_light_rays)
-
-        // let outgoing = LightResult::from([("out1".into(), LightData::Geometric(rays))]);
-        // light_result_to_light_rays(outgoing)
-    }
-}
-
-impl Surface for Source {
-    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
-        &mut self.surface
     }
 }
 
diff --git a/opossum/src/nodes/spectrometer.rs b/opossum/src/nodes/spectrometer.rs
index 91c8608b..6e514b46 100644
--- a/opossum/src/nodes/spectrometer.rs
+++ b/opossum/src/nodes/spectrometer.rs
@@ -14,13 +14,13 @@ use crate::{
     light_result::LightResult,
     lightdata::LightData,
     nanometer,
-    optic_node::OpticNode,
+    optic_node::{OpticNode, LIDT},
     optic_ports::{OpticPorts, PortType},
     plottable::{PlotArgs, PlotParameters, PlotSeries, PlotType, Plottable},
     properties::{Properties, Proptype},
     rays::Rays,
     reporting::node_report::NodeReport,
-    surface::{OpticalSurface, Plane, Surface},
+    surface::{OpticalSurface, Plane},
     utils::geom_transformation::Isometry,
 };
 use std::fmt::{Debug, Display};
@@ -213,10 +213,8 @@ impl OpticNode for Spectrometer {
         self.light_data = None;
         self.surface.reset_hit_map();
     }
-}
-impl Surface for Spectrometer {
     fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
-        todo!()
+        &mut self.surface
     }
 }
 
@@ -245,6 +243,7 @@ impl Dottable for Spectrometer {
         "lightseagreen"
     }
 }
+impl LIDT for Spectrometer {}
 impl Analyzable for Spectrometer {}
 impl AnalysisGhostFocus for Spectrometer {}
 impl AnalysisEnergy for Spectrometer {
diff --git a/opossum/src/nodes/spot_diagram.rs b/opossum/src/nodes/spot_diagram.rs
index 398cfaec..29a216c5 100644
--- a/opossum/src/nodes/spot_diagram.rs
+++ b/opossum/src/nodes/spot_diagram.rs
@@ -19,13 +19,13 @@ use crate::{
     light_result::{LightRays, LightResult},
     lightdata::LightData,
     nanometer,
-    optic_node::{Alignable, OpticNode},
+    optic_node::{Alignable, OpticNode, LIDT},
     optic_ports::{OpticPorts, PortType},
     plottable::{AxLims, PlotArgs, PlotData, PlotParameters, PlotSeries, PlotType, Plottable},
     properties::{Properties, Proptype},
     rays::Rays,
     reporting::node_report::NodeReport,
-    surface::{hit_map::HitMap, OpticalSurface, Plane, Surface},
+    surface::{hit_map::HitMap, OpticalSurface, Plane},
     utils::{
         geom_transformation::Isometry,
         unit_format::{
@@ -96,12 +96,6 @@ impl SpotDiagram {
         sd
     }
 }
-impl Surface for SpotDiagram {
-    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
-        &mut self.surface
-    }
-}
-
 impl Alignable for SpotDiagram {}
 
 impl OpticNode for SpotDiagram {
@@ -190,6 +184,9 @@ impl OpticNode for SpotDiagram {
         self.light_data = None;
         self.surface.reset_hit_map();
     }
+    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
+        &mut self.surface
+    }
 }
 
 impl Dottable for SpotDiagram {
@@ -197,6 +194,7 @@ impl Dottable for SpotDiagram {
         "darkorange"
     }
 }
+impl LIDT for SpotDiagram {}
 impl Analyzable for SpotDiagram {}
 impl AnalysisGhostFocus for SpotDiagram {
     fn analyze(
diff --git a/opossum/src/nodes/thin_mirror.rs b/opossum/src/nodes/thin_mirror.rs
index f9f42b65..e313c23e 100644
--- a/opossum/src/nodes/thin_mirror.rs
+++ b/opossum/src/nodes/thin_mirror.rs
@@ -12,10 +12,11 @@ use crate::{
     light_result::LightResult,
     lightdata::LightData,
     millimeter,
-    optic_node::{Alignable, OpticNode},
+    optic_node::{Alignable, OpticNode, LIDT},
     optic_ports::{OpticPorts, PortType},
     properties::Proptype,
-    surface::{OpticalSurface, Plane, Sphere, Surface},
+    surface::{OpticalSurface, Plane, Sphere},
+    utils::geom_transformation::Isometry,
 };
 use num::Zero;
 use uom::si::f64::Length;
@@ -36,6 +37,7 @@ use uom::si::f64::Length;
 ///   - `curvature`
 pub struct ThinMirror {
     node_attr: NodeAttr,
+    surface: OpticalSurface,
 }
 impl Default for ThinMirror {
     /// Create a thin mirror with a flat surface.
@@ -60,7 +62,11 @@ impl Default for ThinMirror {
             .unwrap();
         ports.add(&PortType::Output, "reflected").unwrap();
         node_attr.set_ports(ports);
-        Self { node_attr }
+
+        Self {
+            node_attr,
+            surface: OpticalSurface::new(Box::new(Plane::new(&Isometry::identity()))),
+        }
     }
 }
 impl ThinMirror {
@@ -89,6 +95,7 @@ impl ThinMirror {
             ));
         }
         self.node_attr.set_property("curvature", curvature.into())?;
+        self.update_surfaces()?;
         Ok(self)
     }
 }
@@ -99,6 +106,17 @@ impl OpticNode for ThinMirror {
     fn node_attr_mut(&mut self) -> &mut NodeAttr {
         &mut self.node_attr
     }
+    fn update_surfaces(&mut self) -> OpmResult<()> {
+        let Ok(Proptype::Length(roc)) = self.node_attr.get_property("curvature") else {
+            return Err(OpossumError::Analysis("cannot read curvature".into()));
+        };
+        self.surface = if roc.is_infinite() {
+            OpticalSurface::new(Box::new(Plane::new(&Isometry::identity())))
+        } else {
+            OpticalSurface::new(Box::new(Sphere::new(*roc, &Isometry::identity())?))
+        };
+        Ok(())
+    }
     #[cfg(feature = "bevy")]
     fn mesh(&self) -> Mesh {
         #[allow(clippy::cast_possible_truncation)]
@@ -118,11 +136,8 @@ impl OpticNode for ThinMirror {
             mesh
         }
     }
-}
-
-impl Surface for ThinMirror {
     fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
-        todo!()
+        &mut self.surface
     }
 }
 
@@ -133,6 +148,7 @@ impl Dottable for ThinMirror {
         "aliceblue"
     }
 }
+impl LIDT for ThinMirror {}
 impl Analyzable for ThinMirror {}
 impl AnalysisGhostFocus for ThinMirror {}
 impl AnalysisEnergy for ThinMirror {
@@ -163,23 +179,17 @@ impl AnalysisRayTrace for ThinMirror {
             return Ok(LightResult::default());
         };
         if let LightData::Geometric(mut rays) = data.clone() {
-            let Ok(Proptype::Length(roc)) = self.node_attr.get_property("curvature") else {
-                return Err(OpossumError::Analysis("curvature".into()));
-            };
             let reflected = if let Some(iso) = self.effective_iso() {
-                let mut surface = if roc.is_infinite() {
-                    OpticalSurface::new(Box::new(Plane::new(&iso)))
-                } else {
-                    OpticalSurface::new(Box::new(Sphere::new(*roc, &iso)?))
-                };
-                surface.set_coating(
-                    self.node_attr()
-                        .ports()
-                        .coating(&PortType::Input, "input")
-                        .unwrap()
-                        .clone(),
-                );
-                let mut reflected_rays = rays.refract_on_surface(&mut surface, None)?;
+                let coating = self
+                    .node_attr()
+                    .ports()
+                    .coating(&PortType::Input, "input")
+                    .unwrap()
+                    .clone();
+                let surface = self.get_surface_mut("");
+                surface.set_isometry(&iso);
+                surface.set_coating(coating);
+                let mut reflected_rays = rays.refract_on_surface(surface, None)?;
                 if let Some(aperture) = self.ports().aperture(&PortType::Input, inport) {
                     reflected_rays.apodize(aperture)?;
                     reflected_rays.invalidate_by_threshold_energy(config.min_energy_per_ray())?;
diff --git a/opossum/src/nodes/wavefront.rs b/opossum/src/nodes/wavefront.rs
index dc62f47d..3ac9f27b 100644
--- a/opossum/src/nodes/wavefront.rs
+++ b/opossum/src/nodes/wavefront.rs
@@ -16,12 +16,12 @@ use crate::{
     light_result::LightResult,
     lightdata::LightData,
     nanometer,
-    optic_node::{Alignable, OpticNode},
+    optic_node::{Alignable, OpticNode, LIDT},
     optic_ports::{OpticPorts, PortType},
     plottable::{AxLims, PlotArgs, PlotData, PlotParameters, PlotSeries, PlotType, Plottable},
     properties::{Properties, Proptype},
     reporting::node_report::NodeReport,
-    surface::{OpticalSurface, Plane, Surface},
+    surface::{OpticalSurface, Plane},
     utils::{
         geom_transformation::Isometry,
         griddata::{create_linspace_axes, interpolate_3d_scatter_data},
@@ -269,6 +269,9 @@ impl OpticNode for WaveFront {
         self.light_data = None;
         self.surface.reset_hit_map();
     }
+    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
+        &mut self.surface
+    }
 }
 impl From<WaveFrontData> for Proptype {
     fn from(value: WaveFrontData) -> Self {
@@ -280,11 +283,8 @@ impl Dottable for WaveFront {
         "goldenrod1"
     }
 }
-impl Surface for WaveFront {
-    fn get_surface_mut(&mut self, _surf_name: &str) -> &mut OpticalSurface {
-        todo!()
-    }
-}
+
+impl LIDT for WaveFront {}
 impl Analyzable for WaveFront {}
 impl AnalysisGhostFocus for WaveFront {}
 impl AnalysisEnergy for WaveFront {
diff --git a/opossum/src/nodes/wedge/analysis_ghostfocus.rs b/opossum/src/nodes/wedge/analysis_ghostfocus.rs
index a6d09454..ea419308 100644
--- a/opossum/src/nodes/wedge/analysis_ghostfocus.rs
+++ b/opossum/src/nodes/wedge/analysis_ghostfocus.rs
@@ -27,9 +27,10 @@ impl AnalysisGhostFocus for Wedge {
         let in_port = &self.ports().names(&PortType::Input)[0];
         let out_port = &self.ports().names(&PortType::Output)[0];
 
-        let Some(incoming_rays) = incoming_data.get(in_port) else {
-            return Ok(LightRays::default());
-        };
+        let mut rays_bundle = incoming_data
+            .get(in_port)
+            .map_or_else(Vec::<Rays>::new, std::clone::Clone::clone);
+
         let (eff_iso, refri, center_thickness, wedge) =
             self.get_node_attributes_ray_trace(&self.node_attr)?;
         let thickness_iso: Isometry = Isometry::new_along_z(center_thickness)?;
@@ -53,8 +54,6 @@ impl AnalysisGhostFocus for Wedge {
             )?;
         };
 
-        let mut rays_bundle = incoming_rays.clone();
-
         self.enter_through_surface(
             &mut rays_bundle,
             &AnalyzerType::GhostFocus(config.clone()),
diff --git a/opossum/src/nodes/wedge/mod.rs b/opossum/src/nodes/wedge/mod.rs
index ac949d8c..3cf84605 100644
--- a/opossum/src/nodes/wedge/mod.rs
+++ b/opossum/src/nodes/wedge/mod.rs
@@ -6,11 +6,11 @@ use crate::{
     dottable::Dottable,
     error::OpmResult,
     millimeter,
-    optic_node::{Alignable, OpticNode},
+    optic_node::{Alignable, OpticNode, LIDT},
     optic_ports::{OpticPorts, PortType},
     rays::Rays,
     refractive_index::{RefrIndexConst, RefractiveIndex, RefractiveIndexType},
-    surface::{hit_map::HitMap, OpticalSurface, Plane, Surface},
+    surface::{hit_map::HitMap, OpticalSurface, Plane},
     utils::{geom_transformation::Isometry, EnumProxy},
 };
 use num::Zero;
@@ -124,16 +124,6 @@ impl Wedge {
     }
 }
 
-impl Surface for Wedge {
-    fn get_surface_mut(&mut self, surf_name: &str) -> &mut OpticalSurface {
-        if surf_name == "front" {
-            &mut self.front_surf
-        } else {
-            &mut self.rear_surf
-        }
-    }
-}
-
 impl OpticNode for Wedge {
     fn reset_data(&mut self) {
         self.front_surf.set_backwards_rays_cache(Vec::<Rays>::new());
@@ -156,6 +146,13 @@ impl OpticNode for Wedge {
     fn node_attr_mut(&mut self) -> &mut NodeAttr {
         &mut self.node_attr
     }
+    fn get_surface_mut(&mut self, surf_name: &str) -> &mut OpticalSurface {
+        if surf_name == "front" {
+            &mut self.front_surf
+        } else {
+            &mut self.rear_surf
+        }
+    }
 }
 
 impl Alignable for Wedge {}
@@ -166,6 +163,7 @@ impl Dottable for Wedge {
     }
 }
 impl Analyzable for Wedge {}
+impl LIDT for Wedge {}
 
 #[cfg(test)]
 mod test {
diff --git a/opossum/src/opm_document.rs b/opossum/src/opm_document.rs
index fe352971..43d0473c 100644
--- a/opossum/src/opm_document.rs
+++ b/opossum/src/opm_document.rs
@@ -138,6 +138,7 @@ mod test {
         assert_eq!(document.opm_file_version, env!("OPM_FILE_VERSION"));
         assert!(document.analyzers.is_empty());
     }
+
     #[test]
     fn from_file() {
         let result =
diff --git a/opossum/src/optic_node.rs b/opossum/src/optic_node.rs
index 225492e4..7e0f0245 100644
--- a/opossum/src/optic_node.rs
+++ b/opossum/src/optic_node.rs
@@ -8,18 +8,19 @@ use petgraph::stable_graph::NodeIndex;
 use uom::si::f64::{Angle, Length};
 
 use crate::{
+    analyzers::Analyzable,
     aperture::Aperture,
     coatings::CoatingType,
     dottable::Dottable,
     error::{OpmResult, OpossumError},
     lightdata::LightData,
-    nodes::{NodeAttr, NodeGroup, NodeReference},
+    nodes::{fluence_detector::Fluence, NodeAttr, NodeGroup, NodeReference},
     optic_ports::{OpticPorts, PortType},
     optic_senery_rsc::SceneryResources,
     properties::{Properties, Proptype},
     refractive_index::RefractiveIndexType,
     reporting::node_report::NodeReport,
-    surface::hit_map::HitMap,
+    surface::{hit_map::HitMap, OpticalSurface},
     utils::geom_transformation::Isometry,
 };
 use core::fmt::Debug;
@@ -134,8 +135,29 @@ pub trait OpticNode: Dottable {
     /// # Errors
     /// This function will return an error if the overwritten function generates an error.
     fn after_deserialization_hook(&mut self) -> OpmResult<()> {
+        self.update_lidt();
+        self.update_surfaces()?;
         Ok(())
     }
+    ///update the surfaces of this node after deserialization
+    /// # Errors
+    /// this function might error in a non-default implementation
+    fn update_surfaces(&mut self) -> OpmResult<()> {
+        Ok(())
+    }
+    ///updates the lidt of the optical surfaces after deserialization
+    fn update_lidt(&mut self) {
+        let lidt = *self.node_attr().lidt();
+        let in_ports = self.ports().names(&PortType::Input);
+        let out_ports = self.ports().names(&PortType::Output);
+
+        for port_name in &in_ports {
+            self.get_surface_mut(port_name).set_lidt(lidt);
+        }
+        for port_name in &out_ports {
+            self.get_surface_mut(port_name).set_lidt(lidt);
+        }
+    }
     /// Return a downcasted mutable reference of a [`NodeReference`].
     ///
     /// # Errors
@@ -230,6 +252,7 @@ pub trait OpticNode: Dottable {
         node_attr_mut.set_ports(node_attributes.ports().clone());
 
         node_attr_mut.set_uuid(node_attributes.uuid());
+        node_attr_mut.set_lidt(node_attributes.lidt());
     }
     /// Get the node type of this [`OpticNode`]
     fn node_type(&self) -> String {
@@ -309,6 +332,9 @@ pub trait OpticNode: Dottable {
             |conf| conf.borrow().ambient_refr_index.clone(),
         )
     }
+
+    ///returns a mutable reference to an optical surface
+    fn get_surface_mut(&mut self, surf_name: &str) -> &mut OpticalSurface;
 }
 impl Debug for dyn OpticNode {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -361,3 +387,22 @@ pub trait Alignable: OpticNode + Sized {
         self
     }
 }
+
+///trait to define an LIDT for a node
+pub trait LIDT: OpticNode + Analyzable + Sized {
+    ///sets an LIDT value for all surfaces of this node
+    #[must_use]
+    fn with_lidt(mut self, lidt: Fluence) -> Self {
+        let in_ports = self.ports().names(&PortType::Input);
+        let out_ports = self.ports().names(&PortType::Output);
+
+        for port_name in &in_ports {
+            self.get_surface_mut(port_name).set_lidt(lidt);
+        }
+        for port_name in &out_ports {
+            self.get_surface_mut(port_name).set_lidt(lidt);
+        }
+        self.node_attr_mut().set_lidt(&lidt);
+        self
+    }
+}
diff --git a/opossum/src/ray.rs b/opossum/src/ray.rs
index 7fc28160..4d8b2a98 100644
--- a/opossum/src/ray.rs
+++ b/opossum/src/ray.rs
@@ -17,7 +17,7 @@ use crate::{
     joule, meter,
     nodes::FilterType,
     spectrum::Spectrum,
-    surface::{GeoSurface, OpticalSurface},
+    surface::OpticalSurface,
     utils::geom_transformation::Isometry,
 };
 
@@ -368,7 +368,7 @@ impl Ray {
     /// This function panics if the diffraction order cannot be converted to f64
     pub fn diffract_on_periodic_surface(
         &mut self,
-        s: &dyn GeoSurface,
+        s: &OpticalSurface,
         n2: f64,
         grating_vector: Vector3<f64>,
         diffraction_order: &i32,
@@ -378,7 +378,9 @@ impl Ray {
                 "the refractive index must be >=1.0 and finite".into(),
             ));
         }
-        if let Some((intersection_point, surface_normal)) = s.calc_intersect_and_normal(self) {
+        if let Some((intersection_point, surface_normal)) =
+            s.geo_surface().calc_intersect_and_normal(self)
+        {
             let surface_normal = surface_normal.normalize();
 
             // get correctly normalized k vector of ray
@@ -403,6 +405,7 @@ impl Ray {
                 self.refractive_index * meter!((pos_in_m - intersection_in_m).norm());
             //then add additional phase shift due to lateral displacement from the grating origin
             let dist_from_origin = s
+                .geo_surface()
                 .isometry()
                 .inverse_transform_point_f64(&intersection_in_m)
                 .x;
diff --git a/opossum/src/rays.rs b/opossum/src/rays.rs
index a32e998c..07a3a1ce 100644
--- a/opossum/src/rays.rs
+++ b/opossum/src/rays.rs
@@ -18,7 +18,7 @@ use crate::{
     refractive_index::RefractiveIndexType,
     spectral_distribution::SpectralDistribution,
     spectrum::Spectrum,
-    surface::{GeoSurface, OpticalSurface},
+    surface::OpticalSurface,
     utils::{
         filter_data::{get_min_max_filter_nonfinite, get_unique_finite_values},
         geom_transformation::Isometry,
@@ -833,7 +833,7 @@ impl Rays {
     /// This function only propagates errors of contained functions.
     pub fn diffract_on_periodic_surface(
         &mut self,
-        surface: &dyn GeoSurface,
+        surface: &OpticalSurface,
         refractive_index: &RefractiveIndexType,
         grating_vector: Vector3<f64>,
         diffraction_order: &i32,
diff --git a/opossum/src/surface/hit_map.rs b/opossum/src/surface/hit_map.rs
index e3baf612..e7c835b3 100644
--- a/opossum/src/surface/hit_map.rs
+++ b/opossum/src/surface/hit_map.rs
@@ -95,6 +95,11 @@ impl RaysHitMap {
         let mut energy = DVector::<f64>::zeros(self.hit_map.len());
         let mut energy_in_ray_bundle = 0.;
 
+        if self.hit_map.len() < 3 {
+            warn!("Too few points on hitmap to calculate fluence!");
+            return Ok(None);
+        }
+
         for (row, p) in self.hit_map.iter().enumerate() {
             pos_in_cm[(row, 0)] = p.0.x.get::<centimeter>();
             pos_in_cm[(row, 1)] = p.0.y.get::<centimeter>();
@@ -211,19 +216,6 @@ impl HitMap {
         &self.critical_fluence
     }
 
-    // pub fn get_critical_fluences(&self) -> OpmResult<Vec<(Uuid, usize, Fluence, Fluence)>>{
-    //     let max_fluence = J_per_cm2!(0.02);
-    //     let mut critical_positions = Vec::<(Uuid, usize, Fluence, Fluence)>::new();
-    //     for (bounce, bounced_hit_map) in self.hit_map.iter().enumerate(){
-    //         for (uuid, rays_hit_map) in &bounced_hit_map.hit_map{
-    //             if let Some((_vdat, _x_lim, _y_lim, average_fluence, peak_fluence)) = rays_hit_map.calc_fluence(max_fluence)?{
-    //                 critical_positions.push((uuid.clone(), bounce, average_fluence, peak_fluence));
-    //             }
-    //         }
-    //     }
-    //     Ok(critical_positions)
-    // }
-
     ///stores a critical fluence in a hitmap
     pub fn add_critical_fluence(&mut self, uuid: &Uuid, rays_hist_pos: usize, fluence: Fluence) {
         self.critical_fluence
diff --git a/opossum/src/surface/mod.rs b/opossum/src/surface/mod.rs
index c174fcad..5377bd20 100644
--- a/opossum/src/surface/mod.rs
+++ b/opossum/src/surface/mod.rs
@@ -62,9 +62,3 @@ impl Debug for dyn GeoSurface {
         write!(f, "Surface")
     }
 }
-
-///Surface trait
-pub trait Surface {
-    ///returns a mutable reference to the surface with a given name
-    fn get_surface_mut(&mut self, surf_name: &str) -> &mut OpticalSurface;
-}
diff --git a/opossum/src/surface/optical_surface.rs b/opossum/src/surface/optical_surface.rs
index 55670ced..9000b04b 100644
--- a/opossum/src/surface/optical_surface.rs
+++ b/opossum/src/surface/optical_surface.rs
@@ -1,3 +1,4 @@
+use log::warn;
 use nalgebra::Point3;
 use uom::si::f64::{Energy, Length};
 use uuid::Uuid;
@@ -30,7 +31,7 @@ impl Default for OpticalSurface {
             backward_rays_cache: Vec::<Rays>::new(),
             forward_rays_cache: Vec::<Rays>::new(),
             hit_map: HitMap::default(),
-            lidt: J_per_cm2!(0.1),
+            lidt: J_per_cm2!(1.0),
         }
     }
 }
@@ -56,7 +57,7 @@ impl OpticalSurface {
             backward_rays_cache: Vec::<Rays>::new(),
             forward_rays_cache: Vec::<Rays>::new(),
             hit_map: HitMap::default(),
-            lidt: J_per_cm2!(0.1),
+            lidt: J_per_cm2!(1.0),
         }
     }
     /// Returns a reference to the coating of this [`OpticalSurface`].
@@ -147,4 +148,18 @@ impl OpticalSurface {
         }
         Ok(())
     }
+
+    ///returns a reference to the lidt value of this [`OpticalSurface`]
+    #[must_use]
+    pub fn lidt(&self) -> &Fluence {
+        &self.lidt
+    }
+    ///set the lidt of this [`OpticalSurface`]
+    pub fn set_lidt(&mut self, lidt: Fluence) {
+        if lidt.is_sign_negative() || !lidt.is_normal() {
+            warn!("LIDT values mut be > 0 and finite! Using default value of 1 J/cm²");
+            return;
+        }
+        self.lidt = lidt;
+    }
 }
-- 
GitLab