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