diff --git a/opossum/examples/ghost_focus.rs b/opossum/examples/ghost_focus.rs
index e210173197ce03d2c847130763698d5ff9e2ec6e..424d1745205ad1a39df7890382c10439cfce26ca 100644
--- a/opossum/examples/ghost_focus.rs
+++ b/opossum/examples/ghost_focus.rs
@@ -22,15 +22,6 @@ fn main() -> OpmResult<()> {
 
     let mut lens = Lens::default();
 
-    // let mut lens = Wedge::new(
-    //     "Wedge",
-    //     millimeter!(10.0),
-    //     degree!(1.0),
-    //     &RefrIndexConst::new(1.5)?,
-    // )?;
-
-    // let mut lens = CylindricLens::default();
-
     lens.set_coating(&PortType::Input, "front", &CoatingType::Fresnel)?;
     lens.set_coating(&PortType::Output, "rear", &CoatingType::Fresnel)?;
     let i_l = scenery.add_node(lens)?;
@@ -48,10 +39,9 @@ fn main() -> OpmResult<()> {
 
     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_w, "front", millimeter!(80.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_l, "rear", i_sd2, "in1", millimeter!(70.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))?;
 
     let mut doc = OpmDocument::new(scenery);
     let mut config = GhostFocusConfig::default();
diff --git a/opossum/src/html/html_report.html b/opossum/src/html/html_report.html
index f551249ce5b60c9ec764fa283d9f9ca4fd39a6e9..fd33f141eef2351c64eda897ff293a72969fd897 100644
--- a/opossum/src/html/html_report.html
+++ b/opossum/src/html/html_report.html
@@ -1,55 +1,50 @@
 <!DOCTYPE html>
 <html class="h-100" lang="en">
-
-<head>
-  <meta charset="UTF-8" />
-  <meta name="description" content="OPOSSUM Analysis Report" />
-  <meta name="keywords" content="OPOSSUM,Laser,Simulation,Optics" />
-  <meta name="author" content="Udo Eisenbarth" />
-  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
-  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
-  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
-  <title>OPOSSUM Analysis Report</title>
-</head>
-
-<body class="d-flex flex-column h-100">
-  <main class="flex-shrink-0" role="main">
-    <div class="container justify-content-center">
-      <div class="row">
-        <div class="col">
-          <div class="mx-auto p-2" style="width: 150px;">
-            <img src="Logo_square.svg" class="img-fluid" alt="OPOSSUM"/>
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="description" content="OPOSSUM Analysis Report" />
+    <meta name="keywords" content="OPOSSUM,Laser,Simulation,Optics" />
+    <meta name="author" content="Udo Eisenbarth" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
+    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
+    <title>OPOSSUM Analysis Report</title>
+  </head>
+  <body class="d-flex flex-column h-100">
+    <main class="flex-shrink-0" role="main">
+      <div class="container justify-content-center">
+        <div class="row">
+          <div class="col">
+            <div class="mx-auto p-2" style="width: 150px;">
+              <img src="Logo_square.svg" class="img-fluid" alt="OPOSSUM"/>
+            </div>
           </div>
         </div>
-      </div>
-      <div class="row">
-        <div class="col">
-            <h1 class="text-center">{analysis_type} Report</h1>
-        </div>
-      </div>
-      <div class="row">
-        <div class="col-md-6 text-start">
-          <span class="small">OPOSSUM version: {opossum_version}</span>
+        <div class="row">
+          <div class="col">
+              <h1 class="text-center">{analysis_type} Report</h1>
+          </div>
         </div>
-        <div class="col-md-6 text-end">
-          <span class="small">Analysis date: {analysis_timestamp}</span>
+        <div class="row">
+          <div class="col-md-6 text-start">
+            <span class="small">OPOSSUM version: {opossum_version}</span>
+          </div>
+          <div class="col-md-6 text-end">
+            <span class="small">Analysis date: {analysis_timestamp}</span>
+          </div>
         </div>
-      </div>
-      <hr/>
-      <div class="row">
-        <div class="col">
-            <h3>{description}</h3>
-            <div class="text-center">
-              <img src="scenery.svg" class="img-fluid" style="max-height: 600pt;" alt="Optical scene diagram"/>
-            </div>
+        <hr/>
+        <div class="row">
+          <div class="col">
+              <h3>{description}</h3>
+              <div class="text-center">
+                <img src="scenery.svg" class="img-fluid" style="max-height: 600pt;" alt="Optical scene diagram"/>
+              </div>
+          </div>
         </div>
+        {{ for node_report in node_reports}}{{ call node_report with node_report }}{{ endfor }}
       </div>
-      {{ for node_report in node_reports}}
-        {{ call node_report with node_report }}
-      {{ endfor }}
-    </div>
-  </main>
-  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
-</body>
-
+    </main>
+    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
+  </body>
 </html>
\ No newline at end of file
diff --git a/opossum/src/html/node_report.html b/opossum/src/html/node_report.html
index 0a9b5cf34e9799258991c89880c57290aefe8a1b..ca40378d53795ded76dc1fc2b92ae4e448a50753 100644
--- a/opossum/src/html/node_report.html
+++ b/opossum/src/html/node_report.html
@@ -7,12 +7,10 @@
       <div class="card-body">
         <table class="table table-sm table-bordered">
           <tbody>
-            {{for property in props}}
-            <tr>
+            {{for property in props}}<tr>
               <th class="text-end" scope="row" style="width:20ch"><abbr title="{property.description}">{property.name}</abbr>:</th>
               <td style="width:auto">{property.prop_value | unescaped}</td>
-            </tr>
-            {{ endfor }}
+            </tr>{{ endfor }}
           </tbody>
         </table>
       </div>
diff --git a/opossum/src/nodes/detector.rs b/opossum/src/nodes/detector.rs
index 49a90f28fabb0060935a1ab5fce9f79719402730..1ed6f4613bc09d18225c4a131e5ec24bd4326b0c 100644
--- a/opossum/src/nodes/detector.rs
+++ b/opossum/src/nodes/detector.rs
@@ -12,6 +12,7 @@ use crate::{
     optic_node::OpticNode,
     optic_ports::{OpticPorts, PortType},
     surface::{OpticalSurface, Plane},
+    utils::geom_transformation::Isometry,
 };
 use log::warn;
 use std::fmt::Debug;
@@ -36,6 +37,7 @@ use std::fmt::Debug;
 pub struct Detector {
     light_data: Option<LightData>,
     node_attr: NodeAttr,
+    surface: OpticalSurface,
 }
 impl Default for Detector {
     fn default() -> Self {
@@ -47,6 +49,7 @@ impl Default for Detector {
         Self {
             light_data: Option::default(),
             node_attr,
+            surface: OpticalSurface::new(Box::new(Plane::new(&Isometry::identity()))),
         }
     }
 }
@@ -76,8 +79,7 @@ impl OpticNode for Detector {
     }
     fn reset_data(&mut self) {
         self.light_data = None;
-        todo!();
-        // self.surface.reset_hit_map();
+        self.surface.reset_hit_map();
     }
 }
 
@@ -116,25 +118,25 @@ impl AnalysisRayTrace for Detector {
         incoming_data: LightResult,
         config: &RayTraceConfig,
     ) -> OpmResult<LightResult> {
-        let (inport, outport) = if self.inverted() {
+        let (in_port, out_port) = if self.inverted() {
             ("out1", "in1")
         } else {
             ("in1", "out1")
         };
-        let Some(data) = incoming_data.get(inport) else {
+        let Some(data) = incoming_data.get(in_port) else {
             return Ok(LightResult::default());
         };
         if let LightData::Geometric(rays) = data {
             let mut rays = rays.clone();
             if let Some(iso) = self.effective_iso() {
-                let mut plane = OpticalSurface::new(Box::new(Plane::new(&iso)));
-                rays.refract_on_surface(&mut plane, None)?;
+                self.surface.set_isometry(&iso);
+                rays.refract_on_surface(&mut self.surface, None)?;
             } else {
                 return Err(OpossumError::Analysis(
                     "no location for surface defined. Aborting".into(),
                 ));
             }
-            if let Some(aperture) = self.ports().aperture(&PortType::Input, "in1") {
+            if let Some(aperture) = self.ports().aperture(&PortType::Input, in_port) {
                 let rays_apodized = rays.apodize(aperture)?;
                 if rays_apodized {
                     warn!("Rays have been apodized at input aperture of {}. Results might not be accurate.", self as &mut dyn OpticNode);
@@ -144,18 +146,18 @@ impl AnalysisRayTrace for Detector {
                 return Err(OpossumError::OpticPort("input aperture not found".into()));
             };
             self.light_data = Some(LightData::Geometric(rays.clone()));
-            if let Some(aperture) = self.ports().aperture(&PortType::Output, "out1") {
+            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("input aperture not found".into()));
             };
             Ok(LightResult::from([(
-                outport.into(),
+                out_port.into(),
                 LightData::Geometric(rays),
             )]))
         } else {
-            Ok(LightResult::from([(outport.into(), data.clone())]))
+            Ok(LightResult::from([(out_port.into(), data.clone())]))
         }
     }
 }
diff --git a/opossum/src/nodes/dummy.rs b/opossum/src/nodes/dummy.rs
index d208a94adaf90fa0e9be1a77b2742bd85f5445de..1eb62a3873082aa5aeca4b1915a71e462fe04af6 100644
--- a/opossum/src/nodes/dummy.rs
+++ b/opossum/src/nodes/dummy.rs
@@ -13,6 +13,7 @@ use crate::{
     optic_ports::{OpticPorts, PortType},
     reporting::analysis_report::NodeReport,
     surface::{OpticalSurface, Plane},
+    utils::geom_transformation::Isometry,
 };
 
 #[derive(Debug, Clone)]
@@ -35,6 +36,7 @@ use crate::{
 ///   - `inverted`
 pub struct Dummy {
     node_attr: NodeAttr,
+    surface: OpticalSurface,
 }
 impl Default for Dummy {
     fn default() -> Self {
@@ -43,7 +45,10 @@ impl Default for Dummy {
         ports.add(&PortType::Input, "front").unwrap();
         ports.add(&PortType::Output, "rear").unwrap();
         node_attr.set_ports(ports);
-        Self { node_attr }
+        Self {
+            node_attr,
+            surface: OpticalSurface::new(Box::new(Plane::new(&Isometry::identity()))),
+        }
     }
 }
 impl Dummy {
@@ -92,20 +97,20 @@ impl AnalysisRayTrace for Dummy {
         if let LightData::Geometric(rays) = data {
             let mut rays = rays.clone();
             if let Some(iso) = self.effective_iso() {
-                let mut plane = OpticalSurface::new(Box::new(Plane::new(&iso)));
-                rays.refract_on_surface(&mut plane, None)?;
+                self.surface.set_isometry(&iso);
+                rays.refract_on_surface(&mut self.surface, None)?;
             } else {
                 return Err(OpossumError::Analysis(
                     "no location for surface defined. Aborting".into(),
                 ));
             }
-            if let Some(aperture) = self.ports().aperture(&PortType::Input, "front") {
+            if let Some(aperture) = self.ports().aperture(&PortType::Input, inport) {
                 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, "rear") {
+            if let Some(aperture) = self.ports().aperture(&PortType::Output, outport) {
                 rays.apodize(aperture)?;
                 rays.invalidate_by_threshold_energy(config.min_energy_per_ray())?;
             } else {
@@ -136,6 +141,9 @@ impl OpticNode for Dummy {
     fn node_attr_mut(&mut self) -> &mut NodeAttr {
         &mut self.node_attr
     }
+    fn reset_data(&mut self) {
+        self.surface.reset_hit_map();
+    }
 }
 
 impl Dottable for Dummy {}
diff --git a/opossum/src/nodes/energy_meter.rs b/opossum/src/nodes/energy_meter.rs
index e7cfa5fd8dd7ae485ba2eaa2aba940f7f6c94a67..c2cdd6d5f3160fc633c6478bf7b0b7d8029c6716 100644
--- a/opossum/src/nodes/energy_meter.rs
+++ b/opossum/src/nodes/energy_meter.rs
@@ -14,6 +14,7 @@ use crate::{
     properties::{Properties, Proptype},
     reporting::analysis_report::NodeReport,
     surface::{OpticalSurface, Plane},
+    utils::geom_transformation::Isometry,
 };
 use log::warn;
 use serde::{Deserialize, Serialize};
@@ -66,6 +67,7 @@ pub struct EnergyMeter {
     light_data: Option<LightData>,
     node_attr: NodeAttr,
     apodization_warning: bool,
+    surface: OpticalSurface,
 }
 impl Default for EnergyMeter {
     fn default() -> Self {
@@ -86,6 +88,7 @@ impl Default for EnergyMeter {
             light_data: None,
             node_attr,
             apodization_warning: false,
+            surface: OpticalSurface::new(Box::new(Plane::new(&Isometry::identity()))),
         }
     }
 }
@@ -183,8 +186,7 @@ impl OpticNode for EnergyMeter {
     }
     fn reset_data(&mut self) {
         self.light_data = None;
-        todo!();
-        // self.surface.reset_hit_map();
+        self.surface.reset_hit_map();
     }
 }
 
@@ -235,14 +237,14 @@ impl AnalysisRayTrace for EnergyMeter {
         if let LightData::Geometric(rays) = data {
             let mut rays = rays.clone();
             if let Some(iso) = self.effective_iso() {
-                let mut plane = OpticalSurface::new(Box::new(Plane::new(&iso)));
-                rays.refract_on_surface(&mut plane, None)?;
+                self.surface.set_isometry(&iso);
+                rays.refract_on_surface(&mut self.surface, None)?;
             } else {
                 return Err(OpossumError::Analysis(
                     "no location for surface defined. Aborting".into(),
                 ));
             }
-            if let Some(aperture) = self.ports().aperture(&PortType::Input, "in1") {
+            if let Some(aperture) = self.ports().aperture(&PortType::Input, inport) {
                 let rays_apodized = rays.apodize(aperture)?;
                 if rays_apodized {
                     warn!("Rays have been apodized at input aperture of {}. Results might not be accurate.", self as &mut dyn OpticNode);
@@ -253,7 +255,7 @@ impl AnalysisRayTrace for EnergyMeter {
                 return Err(OpossumError::OpticPort("input aperture not found".into()));
             };
             self.light_data = Some(LightData::Geometric(rays.clone()));
-            if let Some(aperture) = self.ports().aperture(&PortType::Output, "out1") {
+            if let Some(aperture) = self.ports().aperture(&PortType::Output, outport) {
                 rays.apodize(aperture)?;
                 rays.invalidate_by_threshold_energy(config.min_energy_per_ray())?;
             } else {
diff --git a/opossum/src/nodes/fluence_detector.rs b/opossum/src/nodes/fluence_detector.rs
index ecfaa6977b33fd14190fc8722136f9c6963cbe5c..29d9d65d2f0a8f485605f88fb981df7d0fade528 100644
--- a/opossum/src/nodes/fluence_detector.rs
+++ b/opossum/src/nodes/fluence_detector.rs
@@ -23,6 +23,7 @@ use crate::{
     rays::Rays,
     reporting::analysis_report::NodeReport,
     surface::{OpticalSurface, Plane},
+    utils::geom_transformation::Isometry,
 };
 
 ///alias for uom `RadiantExposure`, as this name is rather uncommon to use for laser scientists
@@ -48,6 +49,7 @@ pub struct FluenceDetector {
     light_data: Option<Rays>,
     node_attr: NodeAttr,
     apodization_warning: bool,
+    surface: OpticalSurface,
 }
 impl Default for FluenceDetector {
     /// creates a fluence detector.
@@ -61,6 +63,7 @@ impl Default for FluenceDetector {
             light_data: None,
             node_attr,
             apodization_warning: false,
+            surface: OpticalSurface::new(Box::new(Plane::new(&Isometry::identity()))),
         }
     }
 }
@@ -159,8 +162,7 @@ impl OpticNode for FluenceDetector {
     }
     fn reset_data(&mut self) {
         self.light_data = None;
-        todo!();
-        // self.surface.reset_hit_map();
+        self.surface.reset_hit_map();
     }
 }
 
@@ -187,8 +189,8 @@ impl AnalysisGhostFocus for FluenceDetector {
         };
         let mut rays = bouncing_rays.clone();
         if let Some(iso) = self.effective_iso() {
-            let mut plane = OpticalSurface::new(Box::new(Plane::new(&iso)));
-            rays.refract_on_surface(&mut plane, None)?;
+            self.surface.set_isometry(&iso);
+            rays.refract_on_surface(&mut self.surface, None)?;
         } else {
             return Err(OpossumError::Analysis(
                 "no location for surface defined. Aborting".into(),
@@ -238,14 +240,14 @@ impl AnalysisRayTrace for FluenceDetector {
         if let LightData::Geometric(rays) = data {
             let mut rays = rays.clone();
             if let Some(iso) = self.effective_iso() {
-                let mut plane = OpticalSurface::new(Box::new(Plane::new(&iso)));
-                rays.refract_on_surface(&mut plane, None)?;
+                self.surface.set_isometry(&iso);
+                rays.refract_on_surface(&mut self.surface, None)?;
             } else {
                 return Err(OpossumError::Analysis(
                     "no location for surface defined. Aborting".into(),
                 ));
             }
-            if let Some(aperture) = self.ports().aperture(&PortType::Input, "in1") {
+            if let Some(aperture) = self.ports().aperture(&PortType::Input, inport) {
                 let rays_apodized = rays.apodize(aperture)?;
                 if rays_apodized {
                     warn!("Rays have been apodized at input aperture of {}. Results might not be accurate.", self as &mut dyn OpticNode);
@@ -256,7 +258,7 @@ impl AnalysisRayTrace for FluenceDetector {
                 return Err(OpossumError::OpticPort("input aperture not found".into()));
             };
             self.light_data = Some(rays.clone());
-            if let Some(aperture) = self.ports().aperture(&PortType::Output, "out1") {
+            if let Some(aperture) = self.ports().aperture(&PortType::Output, outport) {
                 rays.apodize(aperture)?;
                 rays.invalidate_by_threshold_energy(config.min_energy_per_ray())?;
             } else {
diff --git a/opossum/src/nodes/ideal_filter.rs b/opossum/src/nodes/ideal_filter.rs
index 0db4850a5fc55519d41966fa0c61f8ce837d9b5a..a198c672f188fae6403bafaa4a21953ce8eb762b 100644
--- a/opossum/src/nodes/ideal_filter.rs
+++ b/opossum/src/nodes/ideal_filter.rs
@@ -14,7 +14,7 @@ use crate::{
     properties::Proptype,
     spectrum::Spectrum,
     surface::{OpticalSurface, Plane},
-    utils::EnumProxy,
+    utils::{geom_transformation::Isometry, EnumProxy},
 };
 use serde::{Deserialize, Serialize};
 
@@ -41,6 +41,7 @@ pub enum FilterType {
 ///   - `filter type`
 pub struct IdealFilter {
     node_attr: NodeAttr,
+    surface: OpticalSurface,
 }
 impl Default for IdealFilter {
     /// Create an ideal filter node with a transmission of 100%.
@@ -61,7 +62,10 @@ impl Default for IdealFilter {
         ports.add(&PortType::Input, "front").unwrap();
         ports.add(&PortType::Output, "rear").unwrap();
         node_attr.set_ports(ports);
-        Self { node_attr }
+        Self {
+            node_attr,
+            surface: OpticalSurface::new(Box::new(Plane::new(&Isometry::identity()))),
+        }
     }
 }
 impl IdealFilter {
@@ -174,6 +178,9 @@ impl OpticNode for IdealFilter {
     fn node_attr_mut(&mut self) -> &mut NodeAttr {
         &mut self.node_attr
     }
+    fn reset_data(&mut self) {
+        self.surface.reset_hit_map();
+    }
 }
 
 impl Dottable for IdealFilter {
@@ -208,11 +215,11 @@ impl AnalysisRayTrace for IdealFilter {
         incoming_data: LightResult,
         config: &RayTraceConfig,
     ) -> OpmResult<LightResult> {
-        let (mut src, mut target) = ("front", "rear");
+        let (mut in_port, mut out_port) = ("front", "rear");
         if self.inverted() {
-            (src, target) = (target, src);
+            (in_port, out_port) = (out_port, in_port);
         }
-        let Some(input) = incoming_data.get(src) else {
+        let Some(input) = incoming_data.get(in_port) else {
             return Ok(LightResult::default());
         };
         let LightData::Geometric(r) = input else {
@@ -222,34 +229,34 @@ impl AnalysisRayTrace for IdealFilter {
         };
         let mut rays = r.clone();
         if let Some(iso) = self.effective_iso() {
-            let mut plane = OpticalSurface::new(Box::new(Plane::new(&iso)));
-            plane.set_coating(
+            self.surface.set_isometry(&iso);
+            self.surface.set_coating(
                 self.ports()
                     .coating(&PortType::Input, "front")
                     .unwrap()
                     .clone(),
             );
-            rays.refract_on_surface(&mut plane, None)?;
+            rays.refract_on_surface(&mut self.surface, None)?;
         } else {
             return Err(OpossumError::Analysis(
                 "no location for surface defined. Aborting".into(),
             ));
         }
         rays.filter_energy(&self.filter_type())?;
-        if let Some(aperture) = self.ports().aperture(&PortType::Input, "front") {
+        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, "rear") {
+        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 light_data = LightData::Geometric(rays);
-        Ok(LightResult::from([(target.into(), light_data)]))
+        Ok(LightResult::from([(out_port.into(), light_data)]))
     }
 }
 
diff --git a/opossum/src/nodes/paraxial_surface.rs b/opossum/src/nodes/paraxial_surface.rs
index a9625aeb043da8e94375d7a6392e65646311ca24..2a637f7f468bae28517cec41743a3eb520c2d839 100644
--- a/opossum/src/nodes/paraxial_surface.rs
+++ b/opossum/src/nodes/paraxial_surface.rs
@@ -124,12 +124,12 @@ impl AnalysisRayTrace for ParaxialSurface {
         incoming_data: LightResult,
         config: &RayTraceConfig,
     ) -> OpmResult<LightResult> {
-        let (src, target) = if self.inverted() {
+        let (in_port, out_port) = if self.inverted() {
             ("rear", "front")
         } else {
             ("front", "rear")
         };
-        let Some(data) = incoming_data.get(src) else {
+        let Some(data) = incoming_data.get(in_port) else {
             return Ok(LightResult::default());
         };
         if let LightData::Geometric(mut rays) = data.clone() {
@@ -148,20 +148,20 @@ impl AnalysisRayTrace for ParaxialSurface {
                     "no location for surface defined. Aborting".into(),
                 ));
             }
-            if let Some(aperture) = self.ports().aperture(&PortType::Input, "front") {
+            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, "rear") {
+            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(target.into(), LightData::Geometric(rays));
+            light_result.insert(out_port.into(), LightData::Geometric(rays));
             Ok(light_result)
         } else {
             Err(crate::error::OpossumError::Analysis(
diff --git a/opossum/src/nodes/ray_propagation_visualizer.rs b/opossum/src/nodes/ray_propagation_visualizer.rs
index 522cb92fecf228c87be3b271c926c4c56acee230..77b4422177f3020fd038229ab1c97e87da0f482f 100644
--- a/opossum/src/nodes/ray_propagation_visualizer.rs
+++ b/opossum/src/nodes/ray_propagation_visualizer.rs
@@ -27,6 +27,7 @@ use crate::{
     rays::Rays,
     reporting::analysis_report::NodeReport,
     surface::{OpticalSurface, Plane},
+    utils::geom_transformation::Isometry,
 };
 /// A ray-propagation monitor
 ///
@@ -48,6 +49,8 @@ pub struct RayPropagationVisualizer {
     light_data: Option<Rays>,
     node_attr: NodeAttr,
     apodization_warning: bool,
+    #[serde(skip)]
+    surface: OpticalSurface,
 }
 impl Default for RayPropagationVisualizer {
     /// create a spot-diagram monitor.
@@ -66,6 +69,7 @@ impl Default for RayPropagationVisualizer {
             light_data: None,
             node_attr,
             apodization_warning: false,
+            surface: OpticalSurface::new(Box::new(Plane::new(&Isometry::identity()))),
         }
     }
 }
@@ -156,9 +160,7 @@ impl OpticNode for RayPropagationVisualizer {
     }
     fn reset_data(&mut self) {
         self.light_data = None;
-        todo!();
-
-        // self.surface.reset_hit_map();
+        self.surface.reset_hit_map();
     }
 }
 
@@ -185,8 +187,8 @@ impl AnalysisGhostFocus for RayPropagationVisualizer {
         };
         let mut rays = bouncing_rays.clone();
         if let Some(iso) = self.effective_iso() {
-            let mut plane = OpticalSurface::new(Box::new(Plane::new(&iso)));
-            rays.refract_on_surface(&mut plane, None)?;
+            self.surface.set_isometry(&iso);
+            rays.refract_on_surface(&mut self.surface, None)?;
         } else {
             return Err(OpossumError::Analysis(
                 "no location for surface defined. Aborting".into(),
@@ -235,14 +237,14 @@ impl AnalysisRayTrace for RayPropagationVisualizer {
         if let LightData::Geometric(rays) = data {
             let mut rays = rays.clone();
             if let Some(iso) = self.effective_iso() {
-                let mut plane = OpticalSurface::new(Box::new(Plane::new(&iso)));
-                rays.refract_on_surface(&mut plane, None)?;
+                self.surface.set_isometry(&iso);
+                rays.refract_on_surface(&mut self.surface, None)?;
             } else {
                 return Err(OpossumError::Analysis(
                     "no location for surface defined. Aborting".into(),
                 ));
             }
-            if let Some(aperture) = self.ports().aperture(&PortType::Input, "in1") {
+            if let Some(aperture) = self.ports().aperture(&PortType::Input, inport) {
                 let rays_apodized = rays.apodize(aperture)?;
                 if rays_apodized {
                     warn!("Rays have been apodized at input aperture of {}. Results might not be accurate.", self as &mut dyn OpticNode);
@@ -253,7 +255,7 @@ impl AnalysisRayTrace for RayPropagationVisualizer {
                 return Err(OpossumError::OpticPort("input aperture not found".into()));
             };
             self.light_data = Some(rays.clone());
-            if let Some(aperture) = self.ports().aperture(&PortType::Output, "out1") {
+            if let Some(aperture) = self.ports().aperture(&PortType::Output, outport) {
                 let rays_apodized = rays.apodize(aperture)?;
                 if rays_apodized {
                     warn!("Rays have been apodized at input aperture of {}. Results might not be accurate.", self as &mut dyn OpticNode);
@@ -421,11 +423,9 @@ impl Plottable for RayPositionHistories {
             .set(&PlotArgs::Legend(false))?;
         Ok(())
     }
-
     fn get_plot_type(&self, plt_params: &PlotParameters) -> PlotType {
         PlotType::MultiLine2D(plt_params.clone())
     }
-
     fn get_plot_series(
         &self,
         _plt_type: &mut PlotType,
diff --git a/opossum/src/nodes/reflective_grating.rs b/opossum/src/nodes/reflective_grating.rs
index 86cbcdfb7c23129c13d00dfbff2c265ed0631df8..651c568da8989d81bb4f40af7c444f93c693ec2c 100644
--- a/opossum/src/nodes/reflective_grating.rs
+++ b/opossum/src/nodes/reflective_grating.rs
@@ -190,9 +190,6 @@ impl AnalysisRayTrace for ReflectiveGrating {
         let Some(data) = incoming_data.get(inport) else {
             return Ok(LightResult::default());
         };
-        // let light_data = match analyzer_type {
-        //     AnalyzerType::Energy => data.clone(),
-        //     AnalyzerType::RayTrace(_) => {
         if let LightData::Geometric(mut rays) = data.clone() {
             let Ok(Proptype::I32(diffraction_order)) =
                 self.node_attr.get_property("diffraction order")
@@ -217,11 +214,9 @@ impl AnalysisRayTrace for ReflectiveGrating {
                     diffraction_order,
                 )?;
 
-                if let Some(aperture) = self.ports().aperture(&PortType::Input, "input") {
+                if let Some(aperture) = self.ports().aperture(&PortType::Input, inport) {
                     diffracted_rays.apodize(aperture)?;
-                    // if let AnalyzerType::RayTrace(config) = analyzer_type {
                     diffracted_rays.invalidate_by_threshold_energy(config.min_energy_per_ray())?;
-                    // }
                     diffracted_rays
                 } else {
                     return Err(OpossumError::OpticPort("input aperture not found".into()));
diff --git a/opossum/src/nodes/spectrometer.rs b/opossum/src/nodes/spectrometer.rs
index ab92d23da7879fbc3cd62a2c42b636a7d4d6bcb9..5db3969289b728f974aff5f9f15ba6814b2f8809 100644
--- a/opossum/src/nodes/spectrometer.rs
+++ b/opossum/src/nodes/spectrometer.rs
@@ -20,6 +20,7 @@ use crate::{
     properties::{Properties, Proptype},
     reporting::analysis_report::NodeReport,
     surface::{OpticalSurface, Plane},
+    utils::geom_transformation::Isometry,
 };
 use std::fmt::{Debug, Display};
 
@@ -72,6 +73,8 @@ pub struct Spectrometer {
     light_data: Option<LightData>,
     node_attr: NodeAttr,
     apodization_warning: bool,
+    #[serde(skip)]
+    surface: OpticalSurface,
 }
 impl Default for Spectrometer {
     /// create an ideal spectrometer.
@@ -93,6 +96,7 @@ impl Default for Spectrometer {
             light_data: None,
             node_attr,
             apodization_warning: false,
+            surface: OpticalSurface::new(Box::new(Plane::new(&Isometry::identity()))),
         }
     }
 }
@@ -199,9 +203,7 @@ impl OpticNode for Spectrometer {
     }
     fn reset_data(&mut self) {
         self.light_data = None;
-        todo!();
-
-        // self.surface.reset_hit_map();
+        self.surface.reset_hit_map();
     }
 }
 
@@ -264,31 +266,27 @@ impl AnalysisRayTrace for Spectrometer {
         if let LightData::Geometric(rays) = data {
             let mut rays = rays.clone();
             if let Some(iso) = self.effective_iso() {
-                let mut plane = OpticalSurface::new(Box::new(Plane::new(&iso)));
-                rays.refract_on_surface(&mut plane, None)?;
+                self.surface.set_isometry(&iso);
+                rays.refract_on_surface(&mut self.surface, None)?;
             } else {
                 return Err(OpossumError::Analysis(
                     "no location for surface defined. Aborting".into(),
                 ));
             }
-            if let Some(aperture) = self.ports().aperture(&PortType::Input, "in1") {
+            if let Some(aperture) = self.ports().aperture(&PortType::Input, inport) {
                 let rays_apodized = rays.apodize(aperture)?;
                 if rays_apodized {
                     warn!("Rays have been apodized at input aperture of {}. Results might not be accurate.", self as &mut dyn OpticNode);
                     self.apodization_warning = true;
                 }
-                // if let AnalyzerType::RayTrace(config) = analyzer_type {
                 rays.invalidate_by_threshold_energy(config.min_energy_per_ray())?;
-                // }
             } else {
                 return Err(OpossumError::OpticPort("input aperture not found".into()));
             };
             self.light_data = Some(LightData::Geometric(rays.clone()));
-            if let Some(aperture) = self.ports().aperture(&PortType::Output, "out1") {
+            if let Some(aperture) = self.ports().aperture(&PortType::Output, outport) {
                 rays.apodize(aperture)?;
-                // if let AnalyzerType::RayTrace(config) = analyzer_type {
                 rays.invalidate_by_threshold_energy(config.min_energy_per_ray())?;
-                // }
             } else {
                 return Err(OpossumError::OpticPort("output aperture not found".into()));
             };
diff --git a/opossum/src/nodes/thin_mirror.rs b/opossum/src/nodes/thin_mirror.rs
index 0609e5bc0d32076014805adf30f414ece48a131f..58e61d075bfd7bac5b52d4a89b60cdfc246ee489 100644
--- a/opossum/src/nodes/thin_mirror.rs
+++ b/opossum/src/nodes/thin_mirror.rs
@@ -174,11 +174,9 @@ impl AnalysisRayTrace for ThinMirror {
                         .clone(),
                 );
                 let mut reflected_rays = rays.refract_on_surface(&mut surface, None)?;
-                if let Some(aperture) = self.ports().aperture(&PortType::Input, "input") {
+                if let Some(aperture) = self.ports().aperture(&PortType::Input, inport) {
                     reflected_rays.apodize(aperture)?;
-                    //if let AnalyzerType::RayTrace(config) = analyzer_type {
                     reflected_rays.invalidate_by_threshold_energy(config.min_energy_per_ray())?;
-                    // }
                     reflected_rays
                 } else {
                     return Err(OpossumError::OpticPort("input aperture not found".into()));
diff --git a/opossum/src/nodes/wavefront.rs b/opossum/src/nodes/wavefront.rs
index 1f5de720cbab427e7f0d16b4cfbe1ed03e8b61e7..d87805fa45bf731e5a4c23c9e1af382c74e2bdc2 100644
--- a/opossum/src/nodes/wavefront.rs
+++ b/opossum/src/nodes/wavefront.rs
@@ -50,6 +50,8 @@ pub struct WaveFront {
     light_data: Option<LightData>,
     node_attr: NodeAttr,
     apodization_warning: bool,
+    #[serde(skip)]
+    surface: OpticalSurface,
 }
 impl Default for WaveFront {
     /// create a wavefront monitor.
@@ -63,6 +65,7 @@ impl Default for WaveFront {
             light_data: None,
             node_attr,
             apodization_warning: false,
+            surface: OpticalSurface::new(Box::new(Plane::new(&Isometry::identity()))),
         }
     }
 }
@@ -264,9 +267,7 @@ impl OpticNode for WaveFront {
     }
     fn reset_data(&mut self) {
         self.light_data = None;
-        todo!();
-
-        // self.surface.reset_hit_map();
+        self.surface.reset_hit_map();
     }
 }
 impl From<WaveFrontData> for Proptype {
@@ -312,31 +313,27 @@ impl AnalysisRayTrace for WaveFront {
         if let LightData::Geometric(rays) = data {
             let mut rays = rays.clone();
             if let Some(iso) = self.effective_iso() {
-                let mut plane = OpticalSurface::new(Box::new(Plane::new(&iso)));
-                rays.refract_on_surface(&mut plane, None)?;
+                self.surface.set_isometry(&iso);
+                rays.refract_on_surface(&mut self.surface, None)?;
             } else {
                 return Err(OpossumError::Analysis(
                     "no location for surface defined. Aborting".into(),
                 ));
             }
-            if let Some(aperture) = self.ports().aperture(&PortType::Input, "in1") {
+            if let Some(aperture) = self.ports().aperture(&PortType::Input, inport) {
                 let rays_apodized = rays.apodize(aperture)?;
                 if rays_apodized {
                     warn!("Rays have been apodized at input aperture of {}. Results might not be accurate.", self as &mut dyn OpticNode);
                     self.apodization_warning = true;
                 }
-                // if let AnalyzerType::RayTrace(config) = analyzer_type {
                 rays.invalidate_by_threshold_energy(config.min_energy_per_ray())?;
-                // }
             } else {
                 return Err(OpossumError::OpticPort("input aperture not found".into()));
             };
             self.light_data = Some(LightData::Geometric(rays.clone()));
-            if let Some(aperture) = self.ports().aperture(&PortType::Output, "out1") {
+            if let Some(aperture) = self.ports().aperture(&PortType::Output, outport) {
                 rays.apodize(aperture)?;
-                // if let AnalyzerType::RayTrace(config) = analyzer_type {
                 rays.invalidate_by_threshold_energy(config.min_energy_per_ray())?;
-                // }
             } else {
                 return Err(OpossumError::OpticPort("output aperture not found".into()));
             };