diff --git a/opossum/Cargo.toml b/opossum/Cargo.toml index 6ec8db8338d8a83df8f771f031b69cb7868b18bc..33f720c6862a90e767521e2b6087d658121cd5ef 100644 --- a/opossum/Cargo.toml +++ b/opossum/Cargo.toml @@ -30,7 +30,6 @@ opm_macros_lib = { path = "opm_macros_lib" } petgraph = { version = "0.7", features = ["serde-1"] } # the graph library uom = {version="0.36", features = ["serde"] } serde = { version = "1", features = ['rc'] } -#serde_yaml = "0.9" ron="0.9" csv = "1" diff --git a/opossum/examples/apodization.rs b/opossum/examples/apodization.rs index 571f71bee26b36e58e08896b079200adf4aad78f..9f5c810d3b00f4a4c7a88374f6d9e00f6a813ca7 100644 --- a/opossum/examples/apodization.rs +++ b/opossum/examples/apodization.rs @@ -25,7 +25,7 @@ fn main() -> OpmResult<()> { RectangleConfig::new(millimeter!(15.), millimeter!(15.), millimeter!(0.0, 0.0))?; let aperture = Aperture::BinaryRectangle(rect_config); - dummy.set_aperture(&PortType::Input, "front", &aperture)?; + dummy.set_aperture(&PortType::Input, "input_1", &aperture)?; let dummy = dummy.with_decenter(millimeter!(-5.0, 5.0, 0.0))?; let i_d = scenery.add_node(dummy)?; diff --git a/opossum/examples/opm_file.rs b/opossum/examples/empty_opm_file.rs similarity index 100% rename from opossum/examples/opm_file.rs rename to opossum/examples/empty_opm_file.rs diff --git a/opossum/examples/folded_telescope.rs b/opossum/examples/folded_telescope.rs index dbce98b7c2052ed93ff91a0f4379b3e041f6b886..62777a1128e4bc7497e9f1a66a89e2b600585513 100644 --- a/opossum/examples/folded_telescope.rs +++ b/opossum/examples/folded_telescope.rs @@ -13,7 +13,6 @@ use opossum::{ nodes::{Lens, NodeGroup, NodeReference, RayPropagationVisualizer, Source, ThinMirror}, optic_node::{Alignable, OpticNode}, position_distributions::Hexapolar, - rays::Rays, refractive_index::RefrIndexSellmeier1, spectral_distribution::Gaussian, utils::geom_transformation::Isometry, @@ -32,18 +31,18 @@ pub fn main() -> OpmResult<()> { nanometer!(300.)..nanometer!(1200.), )?; let mut scenery = NodeGroup::default(); - let rays = Rays::new_collimated_with_spectrum( - &Gaussian::new( + let light_data_builder = LightDataBuilder::Geometric(RayDataBuilder::Collimated { + pos_dist: Hexapolar::new(millimeter!(10.), 10)?.into(), + energy_dist: UniformDist::new(joule!(1.))?.into(), + spect_dist: Gaussian::new( (nanometer!(1054.), nanometer!(1068.)), 1, nanometer!(1054.), nanometer!(8.), 1., - )?, - &UniformDist::new(joule!(1.))?, - &Hexapolar::new(millimeter!(10.), 10)?, - )?; - let light_data_builder = LightDataBuilder::Geometric(RayDataBuilder::Raw(rays)); + )? + .into(), + }); let mut src = Source::new("collimated ray source", light_data_builder); src.set_alignment_wavelength(alignment_wvl)?; src.set_isometry(Isometry::identity())?; diff --git a/opossum/examples/fresnel_coating.rs b/opossum/examples/fresnel_coating.rs index a0883b9c5dc1906cdaa2264ef83d27ace227a56f..9485fdda9229e797562dcf6f63b30f68e790f92c 100644 --- a/opossum/examples/fresnel_coating.rs +++ b/opossum/examples/fresnel_coating.rs @@ -10,8 +10,8 @@ use opossum::{ optic_node::OpticNode, optic_ports::PortType, position_distributions::Grid, - rays::Rays, refractive_index::RefrIndexConst, + spectral_distribution::LaserLines, utils::geom_transformation::Isometry, OpmDocument, }; @@ -19,12 +19,11 @@ use std::path::Path; fn main() -> OpmResult<()> { let mut scenery = NodeGroup::new("Fresnel coating example"); - let rays = Rays::new_collimated( - nanometer!(1000.), - &UniformDist::new(joule!(1.))?, - &Grid::new((millimeter!(9.), millimeter!(9.)), (100, 100))?, - )?; - let light_data_builder = LightDataBuilder::Geometric(RayDataBuilder::Raw(rays)); + let light_data_builder = LightDataBuilder::Geometric(RayDataBuilder::Collimated { + pos_dist: Grid::new((millimeter!(9.), millimeter!(9.)), (100, 100))?.into(), + energy_dist: UniformDist::new(joule!(1.))?.into(), + spect_dist: LaserLines::new(vec![(nanometer!(1000.), 1.0)])?.into(), + }); let mut source = Source::new("src", light_data_builder); source.set_isometry(Isometry::identity())?; let src = scenery.add_node(source)?; diff --git a/opossum/examples/ghost_focus.rs b/opossum/examples/ghost_focus.rs index 0c3bfbd884892ec47e2fc7332b924259026a8e06..0f9c4b8764f39725e50ca8d8cd0fa5c5d5e13bb2 100644 --- a/opossum/examples/ghost_focus.rs +++ b/opossum/examples/ghost_focus.rs @@ -12,7 +12,7 @@ use opossum::{ optic_ports::PortType, position_distributions::HexagonalTiling, radian, - rays::Rays, + spectral_distribution::LaserLines, utils::geom_transformation::Isometry, OpmDocument, }; @@ -21,21 +21,19 @@ use std::path::Path; fn main() -> OpmResult<()> { let mut scenery = NodeGroup::default(); scenery.node_attr_mut().set_name("Folded Telescope"); - - let rays = Rays::new_collimated( - nanometer!(1000.0), - &General2DGaussian::new( + let light_data_builder = LightDataBuilder::Geometric(RayDataBuilder::Collimated { + pos_dist: HexagonalTiling::new(millimeter!(15.0), 25, millimeter!(0.0, 0.))?.into(), + energy_dist: General2DGaussian::new( joule!(2.), millimeter!(0., 0.), millimeter!(8., 8.), 5., radian!(0.), false, - )?, - &HexagonalTiling::new(millimeter!(15.0), 25, millimeter!(0.0, 0.))?, - )?; - - let light_data_builder = LightDataBuilder::Geometric(RayDataBuilder::Raw(rays)); + )? + .into(), + spect_dist: LaserLines::new(vec![(nanometer!(1000.0), 1.0)])?.into(), + }); let mut src = Source::new("collimated ray source", light_data_builder); src.set_isometry(Isometry::identity())?; let i_src = scenery.add_node(src)?; diff --git a/opossum/examples/group_reverse.rs b/opossum/examples/group_reverse.rs index 332cadcb1f1e3637cf66631b8cd1d67436e7b424..f6a66ae308f407a2270c00c794f33a458706d23a 100644 --- a/opossum/examples/group_reverse.rs +++ b/opossum/examples/group_reverse.rs @@ -4,18 +4,21 @@ use num::Zero; use opossum::{ analyzers::AnalyzerType, error::OpmResult, + joule, lightdata::{energy_spectrum_builder::EnergyDataBuilder, light_data_builder::LightDataBuilder}, + nanometer, nodes::{Dummy, EnergyMeter, NodeGroup, Source}, optic_node::OpticNode, - spectrum_helper::create_he_ne_spec, OpmDocument, }; use uom::si::f64::Length; fn main() -> OpmResult<()> { let mut scenery = NodeGroup::new("Inverse Group test"); - let light_data_builder = - LightDataBuilder::Energy(EnergyDataBuilder::Raw(create_he_ne_spec(1.0)?)); + let light_data_builder = LightDataBuilder::Energy(EnergyDataBuilder::LaserLines( + vec![(nanometer!(633.0), joule!(1.0))], + nanometer!(1.0), + )); let i_s = scenery.add_node(Source::new("Source", light_data_builder))?; let mut group = NodeGroup::default(); diff --git a/opossum/examples/hhts/hhts.rs b/opossum/examples/hhts/hhts.rs index 42d9f979d783f7230429464971052582d54dd878..62407dd7028c62e65370a7550b04794ab059ad82 100644 --- a/opossum/examples/hhts/hhts.rs +++ b/opossum/examples/hhts/hhts.rs @@ -25,8 +25,8 @@ use opossum::{ position_distributions::HexagonalTiling, radian, ray::SplittingConfig, - rays::Rays, refractive_index::{refr_index_schott::RefrIndexSchott, RefrIndexSellmeier1}, + spectral_distribution::LaserLines, spectrum::Spectrum, spectrum_helper::generate_filter_spectrum, utils::geom_transformation::Isometry, @@ -35,17 +35,6 @@ use opossum::{ use uom::si::f64::Length; fn main() -> OpmResult<()> { - let wvl_1w = nanometer!(1054.0); - let wvl_2w = wvl_1w / 2.0; - - let energy_1w = joule!(100.0); - let energy_2w = joule!(50.0); - - // let beam_dist_1w = Hexapolar::new(millimeter!(76.05493), 10)?; - let beam_dist_1w = HexagonalTiling::new(millimeter!(100.), 10, millimeter!(0., 0.))?; - let beam_dist_2w = HexagonalTiling::new(millimeter!(100.), 10, millimeter!(1., 1.))?; - // let beam_dist_2w = beam_dist_1w.clone(); - let refr_index_hk9l = RefrIndexSellmeier1::new( 6.14555251E-1, 6.56775017E-1, @@ -75,70 +64,26 @@ fn main() -> OpmResult<()> { )?; // apertures - // let circle_config = CircleConfig::new(millimeter!(25.4), millimeter!(0., 0.))?; - // let a_2inch = Aperture::BinaryCircle(circle_config); let circle_config = CircleConfig::new(millimeter!(12.7), millimeter!(0., 0.))?; let a_1inch = Aperture::BinaryCircle(circle_config); // collimated source - - let rays_1w = Rays::new_collimated( - wvl_1w, - &General2DGaussian::new( - energy_1w, + let light_data_builder = LightDataBuilder::Geometric(RayDataBuilder::Collimated { + pos_dist: HexagonalTiling::new(millimeter!(100.), 10, millimeter!(0., 0.))?.into(), + energy_dist: General2DGaussian::new( + joule!(150.0), millimeter!(0., 0.), millimeter!(60.6389113608, 60.6389113608), 5., radian!(0.), false, - )?, - &beam_dist_1w, - )?; - let mut rays_2w = Rays::new_collimated( - wvl_2w, - &General2DGaussian::new( - energy_2w, - millimeter!(0., 0.), - millimeter!(60.6389113608, 60.6389113608), - 5., - radian!(0.), - false, - )?, - &beam_dist_2w, - )?; - // let rays_1w = Rays::new_uniform_collimated(wvl_1w, energy_1w, &beam_dist_1w)?; - // let mut rays_2w = Rays::new_uniform_collimated(wvl_2w, energy_2w, &beam_dist_2w)?; - - // point source - - // let rays_1w = Rays::new_hexapolar_point_source( - // millimeter!( - // 0., - // 75.0, - // 0., - // ), - // degree!(0.183346572), - // 6, - // wvl_1w, - // energy_1w, - // )?; - // let mut rays_2w = Rays::new_hexapolar_point_source( - // millimeter!( - // 0., - // 75.0, - // 0., - // ), - // degree!(0.183346572), - // 6, - // wvl_2w, - // energy_2w, - // )?; - - let mut rays = rays_1w; - rays.add_rays(&mut rays_2w); + )? + .into(), + spect_dist: LaserLines::new(vec![(nanometer!(1053.0), 1.0), (nanometer!(527.0), 0.5)])? + .into(), + }); let mut scenery = NodeGroup::new("HHT Sensor"); - let light_data_builder = LightDataBuilder::Geometric(RayDataBuilder::Raw(rays)); let mut src = Source::new("Source", light_data_builder); src.set_isometry(Isometry::identity())?; let src = scenery.add_node(src)?; diff --git a/opossum/examples/inverse_beam_splitter_test.rs b/opossum/examples/inverse_beam_splitter_test.rs index aa609df5cd658424ffedb0c2885fc1932708b9fb..bea165416adb0ee5d9b6e51812a64b17dc375e64 100644 --- a/opossum/examples/inverse_beam_splitter_test.rs +++ b/opossum/examples/inverse_beam_splitter_test.rs @@ -2,11 +2,12 @@ use num::Zero; use opossum::{ analyzers::AnalyzerType, error::OpmResult, + joule, lightdata::{energy_spectrum_builder::EnergyDataBuilder, light_data_builder::LightDataBuilder}, + nanometer, nodes::{BeamSplitter, EnergyMeter, NodeGroup, Source}, optic_node::OpticNode, ray::SplittingConfig, - spectrum_helper::create_he_ne_spec, OpmDocument, }; use std::path::Path; @@ -14,8 +15,10 @@ use uom::si::f64::Length; fn main() -> OpmResult<()> { let mut scenery = NodeGroup::new("inverse beam splitter test"); - let light_data_builder = - LightDataBuilder::Energy(EnergyDataBuilder::Raw(create_he_ne_spec(1.0)?)); + let light_data_builder = LightDataBuilder::Energy(EnergyDataBuilder::LaserLines( + vec![(nanometer!(633.0), joule!(1.0))], + nanometer!(1.0), + )); let i_s = scenery.add_node(Source::new("Source", light_data_builder))?; let mut bs = BeamSplitter::new("bs", &SplittingConfig::Ratio(0.6)).unwrap(); bs.set_inverted(true)?; diff --git a/opossum/examples/laser_system.rs b/opossum/examples/laser_system.rs index 6c97f96bce7565e33567618abfdd34912a6765b5..8d7786d9618717321deb3ae5b08526f84c90e53d 100644 --- a/opossum/examples/laser_system.rs +++ b/opossum/examples/laser_system.rs @@ -16,13 +16,6 @@ use uom::si::f64::Length; fn main() -> OpmResult<()> { let mut scenery = NodeGroup::new("laser system"); // Main beam line - - // let source = Source::new( - // "Source", - // &LightData::Energy(DataEnergy { - // spectrum: create_he_ne_spec(1.0)?, - // }), - // ); let source = round_collimated_ray_source(millimeter!(1.0), joule!(1.0), 3)?; let i_src = scenery.add_node(source)?; let i_l1 = scenery.add_node(ParaxialSurface::new("f=100", millimeter!(100.0))?)?; diff --git a/opossum/examples/michaelson.rs b/opossum/examples/michaelson.rs index 9d77f2c81ed57f439e0d30e18e382d14eae967f8..87018a62c9afbbfa66f56c98d1a316a2b6760191 100644 --- a/opossum/examples/michaelson.rs +++ b/opossum/examples/michaelson.rs @@ -2,9 +2,10 @@ use num::Zero; use opossum::{ analyzers::AnalyzerType, error::OpmResult, + joule, lightdata::{energy_spectrum_builder::EnergyDataBuilder, light_data_builder::LightDataBuilder}, + nanometer, nodes::{BeamSplitter, Dummy, NodeGroup, NodeReference, Source}, - spectrum_helper::create_he_ne_spec, OpmDocument, }; use std::path::Path; @@ -12,8 +13,10 @@ use uom::si::f64::Length; fn main() -> OpmResult<()> { let mut scenery = NodeGroup::new("Michaelson interferomater"); - let light_data_builder = - LightDataBuilder::Energy(EnergyDataBuilder::Raw(create_he_ne_spec(1.0)?)); + let light_data_builder = LightDataBuilder::Energy(EnergyDataBuilder::LaserLines( + vec![(nanometer!(633.0), joule!(1.0))], + nanometer!(1.0), + )); let src = scenery.add_node(Source::new("Source", light_data_builder))?; let bs = scenery.add_node(BeamSplitter::default())?; let sample = scenery.add_node(Dummy::new("Sample"))?; diff --git a/opossum/examples/nalgebra_matrix_testing.rs b/opossum/examples/nalgebra_matrix_testing.rs deleted file mode 100644 index 9a65649cc94033bdc6ff0332011f70510b148a35..0000000000000000000000000000000000000000 --- a/opossum/examples/nalgebra_matrix_testing.rs +++ /dev/null @@ -1,212 +0,0 @@ -use itertools::Itertools; -use nalgebra::DVector; -use std::time::Instant; - -fn pairwise_sumation(input: &[f64]) -> f64 { - let sub_array_size = 32; - let vec_len = input.len(); - if vec_len < sub_array_size { - let mut sum = 0.; - for val in input { - sum += *val; - } - sum - } else { - let new_size = vec_len / 2; - pairwise_sumation(&input[..new_size]) + pairwise_sumation(&input[new_size..vec_len]) - } -} - -// fn pairwise_sum_matrix(input: &DVectorView<f64>) -> f64 { -// let vec_len = input.len(); -// if vec_len < 64 { -// input.sum() -// } else { -// let new_size = vec_len / 2; -// pairwise_sum_matrix(&input.rows(0, new_size)) -// + pairwise_sum_matrix(&input.rows(new_size, vec_len - new_size)) -// } -// } - -fn kahansum2(input: Vec<f64>) -> f64 { - // Prepare the accumulator. - // Prepare the accumulator. - let mut sum = 0.0; - // A running compensation for lost low-order bits. - let mut c = 0.0; - // The array input has elements indexed input[1] to input[input.length]. - for i in input.iter() { - // c is zero the first time around. - let y = i - c; - // Alas, sum is big, y small, so low-order digits of y are lost. - let t = sum + y; - // (t - sum) cancels the high-order part of y; - // subtracting y recovers negative (low part of y) - c = (t - sum) - y; - // Algebraically, c should always be zero. Beware - // overly-aggressive optimizing compilers! - sum = t; - // Next time around, the lost low part will be added to y in a fresh attempt. - } - return sum; -} - -fn kahansum_vector(input: &DVector<f64>) -> f64 { - // Prepare the accumulator. - // Prepare the accumulator. - let mut sum = 0.0; - // A running compensation for lost low-order bits. - let mut c = 0.0; - // The array input has elements indexed input[1] to input[input.length]. - for i in input { - // c is zero the first time around. - let y = i - &c; - // Alas, sum is big, y small, so low-order digits of y are lost. - let t = &sum + &y; - // (t - sum) cancels the high-order part of y; - // subtracting y recovers negative (low part of y) - c = (&t - &sum) - &y; - // Algebraically, c should always be zero. Beware - // overly-aggressive optimizing compilers! - sum = t; - // Next time around, the lost low part will be added to y in a fresh attempt. - } - return sum; -} - -fn main() { - // let mat = DVector::from(vec![-3., -2., -1., 0., 1., 2., 3.]); - // let mat2 = MatrixXx1::from(vec![-3., f64::NAN, -2., -1., 1., f64::INFINITY, 3.]); - // let mat22 = MatrixXx1::from(vec![f64::NAN, f64::INFINITY]); - // let mat3 = MatrixXx1::from(vec![f64::INFINITY, -2., -1., 0., 1., 2., 3.]); - // let mat4 = MatrixXx1::from(vec![f64::NAN, f64::NAN]); - // let infinite_plus = f64::INFINITY; - // let infinite_minus = -f64::INFINITY; - // let mut vec = Vec::<f64>::new(); - - // let test = mat.rows(0, 5); - // let test = mat.fixed_columns - - // let mat_wo_inf = mat2.iter().filter_map(|x| { - // if !x.is_nan() & x.is_finite(){ - // Some(x.clone()) - // } - // else{ - // None - // } - // }).collect::<Vec<f64>>(); - - // let mat_wo_inf = MatrixXx1::from( - // mat22 - // .iter() - // .cloned() - // .filter(|x| !x.is_nan() & x.is_finite()) - // .collect::<Vec<f64>>(), - // ); - // let bla: Vec<&f64> = mat_wo_inf.to_vec().clone(); - // let test = MatrixXx1::from_vec(bla); - // let mat_new = MatrixXx1::from_vec(mat_wo_inf.clone()); - - // println!("{mat2}"); - // println!("{mat_wo_inf}"); - // println!("{}", mat_wo_inf.len()); - - // // println!("min:\t{}\nmax:\t{}\n", mat.min(), mat.max()); - // println!("min:\t{}\nmax:\t{}\n", mat2.min(), mat2.max()); - // println!("min:\t{}\nmax:\t{}\n", mat3.min(), mat3.max()); - // println!("min:\t{}\nmax:\t{}\n", mat4.min(), mat4.max()); - - // println!("min:\t{}\nmax:\t{}\n", mat_wo_inf.min(), mat_wo_inf.max()); - let s1 = 1000.100; - let s2 = 999.; - let test = (s1 - s2 - 1.1) / s1; - let test = format!("{:+e}", test); - println!("{test}"); - - let energy = 1. + f64::EPSILON; - let num_rays = 1000001; - - let energy_per_ray = energy * 1. / num_rays as f64; - - let mut rays_vec2 = Vec::<f64>::with_capacity(num_rays); - for _ in 0..(num_rays as usize) { - rays_vec2.push(energy_per_ray) - } - - let mat = DVector::from_vec(rays_vec2.clone()); - let rays_vec1 = rays_vec2.clone(); - let rays_vec3 = rays_vec2.clone(); - let energy_vec = rays_vec2.iter().fold(0., |a, b| a + b); - - let start = Instant::now(); - let energy_vec0 = kahansum_vector(&mat); //sum_with_accumulator::<NaiveSum<f64>>(); - let duration = start.elapsed(); - println!( - "Time elapsed in kahan matrix summation() is: {:?}", - duration - ); - - let start = Instant::now(); - let energy_vec1 = rays_vec2.iter().cloned().tree_reduce(|a, b| a + b); //sum_with_accumulator::<NaiveSum<f64>>(); - let duration = start.elapsed(); - println!( - "Time elapsed in pariwise itertools summation() is: {:?}", - duration - ); - - let start = Instant::now(); - let energy_vec2 = kahansum2(rays_vec1); - let duration = start.elapsed(); - println!("Time elapsed in kahan summation() is: {:?}", duration); - - let start = Instant::now(); - let energy_vec3 = pairwise_sumation(&rays_vec3[..]); - let duration = start.elapsed(); - println!( - "Time elapsed in pairwise self written summation() is: {:?}", - duration - ); - - println!("energy:{}", energy_vec0); - println!("energy:{}", energy_vec); - println!("energy:{}", energy_vec1.unwrap()); - println!("energy:{}", energy_vec2); - println!("energy:{}", energy_vec3); - - // println!("energy:{}", energy_vec); - // println!("energy:{}", energy_vec2); - // println!("energy:{}", energy_vec3); - // let mut summed_time = Duration::new(0, 0); - // for i in 1..1000{ - // let energy = (i as f64)+f64::EPSILON; - // let num_rays = 1000 * i; - // let energy_per_ray = energy/num_rays as f64; - // let mut rays_vec = Vec::<f64>::with_capacity(num_rays); - // for i in 0..(num_rays as usize){ - // rays_vec.push(energy_per_ray) - // } - // let start = Instant::now(); - // let _ = kahansum2(rays_vec); - // let duration = start.elapsed(); - // summed_time += duration; - - // } - // println!("Time elapsed in kahan summation() is: {:?}", summed_time); - - // let mut summed_time = Duration::new(0, 0); - // for i in 1..1000{ - // let energy = (i as f64)+f64::EPSILON; - // let num_rays = 1000 * i; - // let energy_per_ray = energy/num_rays as f64; - // let mut rays_vec = Vec::<f64>::with_capacity(num_rays); - // for i in 0..(num_rays as usize){ - // rays_vec.push(energy_per_ray) - // } - // let start = Instant::now(); - // let _ = pairwise_sumation(&rays_vec); - // let duration = start.elapsed(); - // summed_time += duration; - - // } - // println!("Time elapsed in pairwise summation() is: {:?}", summed_time); -} diff --git a/opossum/examples/prism_dispersion.rs b/opossum/examples/prism_dispersion.rs index a0e5e96eab9e463aff5d2b709c62ec053dc1b2fd..010d9f62a70fc3f8e3b8dae97d1fc65399287fb2 100644 --- a/opossum/examples/prism_dispersion.rs +++ b/opossum/examples/prism_dispersion.rs @@ -4,6 +4,7 @@ use num::Zero; use opossum::{ analyzers::{AnalyzerType, RayTraceConfig}, degree, + energy_distributions::UniformDist, error::OpmResult, joule, lightdata::{light_data_builder::LightDataBuilder, ray_data_builder::RayDataBuilder}, @@ -11,8 +12,8 @@ use opossum::{ nodes::{NodeGroup, RayPropagationVisualizer, Source, SpotDiagram, Wedge}, optic_node::{Alignable, OpticNode}, position_distributions::Grid, - rays::Rays, refractive_index::RefrIndexSellmeier1, + spectral_distribution::LaserLines, utils::geom_transformation::Isometry, OpmDocument, }; @@ -31,22 +32,14 @@ fn main() -> OpmResult<()> { let beam_size_y = millimeter!(10.0); let nr_of_rays = 5; let wedge_angle_in_degree = 10.0; - let mut rays_1w = Rays::new_uniform_collimated( - nanometer!(1053.), - joule!(1.), - &Grid::new((Length::zero(), beam_size_y), (1, nr_of_rays))?, - )?; - - let mut rays_2w = Rays::new_uniform_collimated( - nanometer!(527.), - joule!(1.), - &Grid::new((Length::zero(), beam_size_y), (1, nr_of_rays))?, - )?; - - rays_1w.add_rays(&mut rays_2w); let mut scenery = NodeGroup::default(); - let light_data_builder = LightDataBuilder::Geometric(RayDataBuilder::Raw(rays_1w)); + let light_data_builder = LightDataBuilder::Geometric(RayDataBuilder::Collimated { + pos_dist: Grid::new((Length::zero(), beam_size_y), (1, nr_of_rays))?.into(), + energy_dist: UniformDist::new(joule!(1.0))?.into(), + spect_dist: LaserLines::new(vec![(nanometer!(1053.0), 1.0), (nanometer!(527.0), 1.0)])? + .into(), + }); let mut light_src = Source::new("collimated ray source", light_data_builder); light_src.set_isometry(Isometry::identity())?; let src = scenery.add_node(light_src)?; diff --git a/opossum/examples/reference_test.rs b/opossum/examples/reference_test.rs index e87695dc71fc463646556f5de62021cd1bb704ec..d0ba6e19047dc5d23fc9f18d1b9fe8dc6c600c43 100644 --- a/opossum/examples/reference_test.rs +++ b/opossum/examples/reference_test.rs @@ -2,9 +2,10 @@ use num::Zero; use opossum::{ analyzers::AnalyzerType, error::OpmResult, + joule, lightdata::{energy_spectrum_builder::EnergyDataBuilder, light_data_builder::LightDataBuilder}, + nanometer, nodes::{EnergyMeter, IdealFilter, NodeGroup, NodeReference, Source}, - spectrum_helper::create_he_ne_spec, OpmDocument, }; use std::path::Path; @@ -12,8 +13,10 @@ use uom::si::f64::Length; fn main() -> OpmResult<()> { let mut scenery = NodeGroup::new("Reference node demo"); - let light_data_builder = - LightDataBuilder::Energy(EnergyDataBuilder::Raw(create_he_ne_spec(1.0)?)); + let light_data_builder = LightDataBuilder::Energy(EnergyDataBuilder::LaserLines( + vec![(nanometer!(633.0), joule!(1.0))], + nanometer!(1.0), + )); let src = scenery.add_node(Source::new("source", light_data_builder))?; let filt = scenery.add_node(IdealFilter::new( "50 % filter", diff --git a/opossum/src/coatings/constant_r.rs b/opossum/src/coatings/constant_r.rs index d412ab4dc36b6649fb0c9e8b0267a08f180011d7..0b3489f3bfc1f39d909c0718009f30c60d2ef6fd 100644 --- a/opossum/src/coatings/constant_r.rs +++ b/opossum/src/coatings/constant_r.rs @@ -38,14 +38,14 @@ impl Coating for ConstantR { ) -> f64 { self.reflectivity } - - fn to_enum(&self) -> super::CoatingType { - CoatingType::ConstantR { - reflectivity: self.reflectivity, +} +impl From<ConstantR> for CoatingType { + fn from(coating: ConstantR) -> Self { + Self::ConstantR { + reflectivity: coating.reflectivity, } } } - #[cfg(test)] mod test { use super::*; @@ -64,10 +64,10 @@ mod test { assert!(ConstantR::new(1.1).is_err()); } #[test] - fn to_enum() { + fn from() { let coating = ConstantR::new(0.5).unwrap(); assert!(matches!( - coating.to_enum(), + coating.into(), CoatingType::ConstantR { reflectivity: 0.5 } )); } diff --git a/opossum/src/coatings/fresnel.rs b/opossum/src/coatings/fresnel.rs index 3a6da68b4c6b7f38c535071c07b11fb0ac38300c..d14f695207551d68ccb341b5468b14b0f5c6d54f 100644 --- a/opossum/src/coatings/fresnel.rs +++ b/opossum/src/coatings/fresnel.rs @@ -32,11 +32,12 @@ impl Coating for Fresnel { // so far, we assume unpolarized (50/50) rays -> take average r_p.mul_add(r_p, r_s.powi(2)) / 2. } - fn to_enum(&self) -> super::CoatingType { - CoatingType::Fresnel +} +impl From<Fresnel> for CoatingType { + fn from(_coating: Fresnel) -> Self { + Self::Fresnel } } - #[cfg(test)] mod test { use super::*; @@ -45,9 +46,9 @@ mod test { use nalgebra::vector; #[test] - fn to_enum() { + fn from() { let coating = Fresnel; - assert!(matches!(coating.to_enum(), CoatingType::Fresnel)); + assert!(matches!(coating.into(), CoatingType::Fresnel)); } #[test] fn calc_refl_same_index() { diff --git a/opossum/src/coatings/ideal_ar.rs b/opossum/src/coatings/ideal_ar.rs index bebd59856fa55df3e67960a4a868b2db124ef246..00cea71b66d01c5e4d5d8de2a52b5f423689219f 100644 --- a/opossum/src/coatings/ideal_ar.rs +++ b/opossum/src/coatings/ideal_ar.rs @@ -19,11 +19,12 @@ impl Coating for IdealAR { ) -> f64 { 0.0 } - fn to_enum(&self) -> super::CoatingType { - CoatingType::IdealAR +} +impl From<IdealAR> for CoatingType { + fn from(_coating: IdealAR) -> Self { + Self::IdealAR } } - #[cfg(test)] mod test { use super::*; @@ -31,9 +32,9 @@ mod test { use nalgebra::vector; #[test] - fn to_enum() { + fn from() { let coating = IdealAR; - assert!(matches!(coating.to_enum(), CoatingType::IdealAR)); + assert!(matches!(coating.into(), CoatingType::IdealAR)); } #[test] fn calc_refl() { diff --git a/opossum/src/coatings/mod.rs b/opossum/src/coatings/mod.rs index ceac2daf17db50a9a2f910ad4ec878b53de57ce6..0c3f2dced19c7539256d4bff6d3a26c9a2edfba1 100644 --- a/opossum/src/coatings/mod.rs +++ b/opossum/src/coatings/mod.rs @@ -63,8 +63,4 @@ pub trait Coating { /// Calculate the reflectivity based on the concrete model for an incoming [`Ray`] on a surface with /// a given `surface_normal` at the intersection point and the refractive index of the following medium. fn calc_reflectivity(&self, incoming_ray: &Ray, surface_normal: Vector3<f64>, n2: f64) -> f64; - /// Return the corresponding [`CoatingType`] for a given [`Coating`]. - /// - /// This function is mainly used for serialization / deserialization. - fn to_enum(&self) -> CoatingType; } diff --git a/opossum/src/console.rs b/opossum/src/console.rs index 7eeaf45ae233e70bc7e987834022a3d6ab196252..18385dc96ed1630961bb39c4a7459fb1186c0d5e 100644 --- a/opossum/src/console.rs +++ b/opossum/src/console.rs @@ -253,13 +253,13 @@ mod test { let path_inexistent_file = Path::new("./files_for_testing/opm/nonexistent.opm"); let path_inexistent_dir = Path::new("./files_for_testing/this_dir_does_not_exist/empty.opm"); - let path_not_yaml = Path::new("./files_for_testing/opm/is_not_a_opm.txt"); + let path_not_opm = Path::new("./files_for_testing/opm/is_not_a_opm.txt"); let path_is_dir = Path::new("./files_for_testing/opm/"); assert_eq!(file_path_is_valid(path_valid), true); assert_eq!(file_path_is_valid(path_inexistent_file), false); assert_eq!(file_path_is_valid(path_inexistent_dir), false); - assert_eq!(file_path_is_valid(path_not_yaml), false); + assert_eq!(file_path_is_valid(path_not_opm), false); assert_eq!(file_path_is_valid(path_is_dir), false); } #[test] @@ -267,7 +267,7 @@ mod test { let path_valid = "./files_for_testing/opm/opticscenery.opm"; let path_inexistent_file = "./files_for_testing/opm/nonexistent.opm"; let path_inexistent_dir = "./files_for_testing/this_dir_does_not_exist/empty.opm"; - let path_not_yaml = "./files_for_testing/opm/is_not_an_opm.txt"; + let path_not_opm = "./files_for_testing/opm/is_not_an_opm.txt"; let path_is_dir = "./files_for_testing/opm/"; assert_eq!( @@ -276,7 +276,7 @@ mod test { ); assert_eq!(eval_file_path_input(path_inexistent_file), None); assert_eq!(eval_file_path_input(path_inexistent_dir), None); - assert_eq!(eval_file_path_input(path_not_yaml), None); + assert_eq!(eval_file_path_input(path_not_opm), None); assert_eq!(eval_file_path_input(path_is_dir), None); } #[test] @@ -295,7 +295,7 @@ mod test { } #[test] fn get_parent_dir_test() { - let path_valid = "./files_for_testing/opm/empty_yaml.yaml".to_owned(); + let path_valid = "./files_for_testing/opm/my_file.opm".to_owned(); assert_eq!( get_parent_dir(&PathBuf::from(path_valid)), PathBuf::from("./files_for_testing/opm") diff --git a/opossum/src/energy_distributions/general_gaussian.rs b/opossum/src/energy_distributions/general_gaussian.rs index 9489459d8b871f23217b2f62701e524ef6adc0db..cb37cec8458cd97e232608674228fd5ea98789b3 100644 --- a/opossum/src/energy_distributions/general_gaussian.rs +++ b/opossum/src/energy_distributions/general_gaussian.rs @@ -8,11 +8,14 @@ use crate::{ }; use kahan::KahanSummator; use nalgebra::Point2; +use serde::{Deserialize, Serialize}; use uom::si::{ angle::radian, energy::joule, f64::{Angle, Energy, Length}, }; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct General2DGaussian { total_energy: Energy, mu_xy: Point2<Length>, @@ -122,7 +125,11 @@ impl EnergyDistribution for General2DGaussian { self.total_energy } } - +impl From<General2DGaussian> for super::EnergyDistType { + fn from(g: General2DGaussian) -> Self { + Self::General2DGaussian(g) + } +} #[cfg(test)] mod test { use super::*; diff --git a/opossum/src/energy_distributions/mod.rs b/opossum/src/energy_distributions/mod.rs index d5a904796d7d54c5360a46debeb395b1960f3d63..22c01756a75f5119afd39cfed062584002172aaf 100644 --- a/opossum/src/energy_distributions/mod.rs +++ b/opossum/src/energy_distributions/mod.rs @@ -1,10 +1,14 @@ //! Module for handling energy distributions -use nalgebra::Point2; -use uom::si::f64::{Energy, Length}; - pub mod general_gaussian; pub mod uniform; +pub use general_gaussian::General2DGaussian; +use serde::{Deserialize, Serialize}; +pub use uniform::UniformDist; + +use crate::joule; use kahan::KahanSummator; +use nalgebra::Point2; +use uom::si::f64::{Energy, Length}; pub trait EnergyDistribution { fn apply(&self, input: &[Point2<Length>]) -> Vec<Energy>; @@ -31,10 +35,18 @@ pub trait EnergyDistribution { } } -pub use general_gaussian::General2DGaussian; -pub use uniform::UniformDist; +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub enum EnergyDistType { + Uniform(UniformDist), + General2DGaussian(general_gaussian::General2DGaussian), +} -use crate::joule; -// pub use hexapolar::Hexapolar; -// pub use random::Random; -// pub use sobol::SobolDist; +impl EnergyDistType { + #[must_use] + pub fn generate(&self) -> &dyn EnergyDistribution { + match self { + Self::Uniform(dist) => dist, + Self::General2DGaussian(dist) => dist, + } + } +} diff --git a/opossum/src/energy_distributions/uniform.rs b/opossum/src/energy_distributions/uniform.rs index 5e7f7233aae49e7a255e0a5a7b70af47adc4cd1d..e5640fe07f69081c5890d1c34c581ae3316a72a5 100644 --- a/opossum/src/energy_distributions/uniform.rs +++ b/opossum/src/energy_distributions/uniform.rs @@ -2,14 +2,15 @@ use nalgebra::Point2; use num::ToPrimitive; +use serde::{Deserialize, Serialize}; use uom::si::{ energy::joule, f64::{Energy, Length}, }; -use crate::error::{OpmResult, OpossumError}; - use super::EnergyDistribution; +use crate::error::{OpmResult, OpossumError}; +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct UniformDist { total_energy: Energy, } @@ -43,7 +44,11 @@ impl EnergyDistribution for UniformDist { self.total_energy } } - +impl From<UniformDist> for super::EnergyDistType { + fn from(ud: UniformDist) -> Self { + Self::Uniform(ud) + } +} #[cfg(test)] mod test { use super::*; diff --git a/opossum/src/lightdata/energy_spectrum_builder.rs b/opossum/src/lightdata/energy_spectrum_builder.rs index b8e46f2b72a5c00dc4b05a3c4029bbfe7020e789..68f392f43f86b2ee35506ec389eb1b731bd72615 100644 --- a/opossum/src/lightdata/energy_spectrum_builder.rs +++ b/opossum/src/lightdata/energy_spectrum_builder.rs @@ -49,4 +49,4 @@ impl Display for EnergyDataBuilder { Self::LaserLines(l, r) => write!(f, "LaserLines({:?}, {})", l, r.value), } } -} \ No newline at end of file +} diff --git a/opossum/src/lightdata/ray_data_builder.rs b/opossum/src/lightdata/ray_data_builder.rs index 5ee4d67b74b2b012be5729795f0356689b4beaf5..f57cb47f21b5b8585bee378cbed639fe94457bd3 100644 --- a/opossum/src/lightdata/ray_data_builder.rs +++ b/opossum/src/lightdata/ray_data_builder.rs @@ -4,16 +4,27 @@ //! This builder allows easier serialization / deserialization in OPM files. use std::fmt::Display; -use crate::{error::OpmResult, rays::Rays}; -use serde::{Deserialize, Serialize}; - use super::LightData; +use crate::{ + energy_distributions::EnergyDistType, error::OpmResult, position_distributions::PosDistType, + rays::Rays, spectral_distribution::SpecDistType, +}; +use serde::{Deserialize, Serialize}; /// Builder for the generation of [`LightData::Geometric`]. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub enum RayDataBuilder { /// Raw [`Rays`] data. Raw(Rays), + /// Collimated [`Rays`] data with a given [`PosDistType`] and [`EnergyDistType`] as well as a given single wavelength. + Collimated { + /// Position distribution. + pos_dist: PosDistType, + /// Energy distribution. + energy_dist: EnergyDistType, + /// Wavelength of the rays. + spect_dist: SpecDistType, + }, } impl RayDataBuilder { @@ -24,6 +35,18 @@ impl RayDataBuilder { pub fn build(self) -> OpmResult<LightData> { match self { Self::Raw(rays) => Ok(LightData::Geometric(rays)), + Self::Collimated { + pos_dist, + energy_dist, + spect_dist, + } => { + let rays = Rays::new_collimated_with_spectrum( + spect_dist.generate(), + energy_dist.generate(), + pos_dist.generate(), + )?; + Ok(LightData::Geometric(rays)) + } } } } @@ -32,6 +55,16 @@ impl Display for RayDataBuilder { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Raw(r) => write!(f, "Raw({r})"), + Self::Collimated { + pos_dist, + energy_dist, + spect_dist, + } => { + write!( + f, + "Collimated({pos_dist:?}, {energy_dist:?}, {spect_dist:?})" + ) + } } } } diff --git a/opossum/src/main.rs b/opossum/src/main.rs index a3c2396c43949e954cc4d28cf55e7a533bcca25c..f88aaca8c6f9ef7ad43e7a3c7d62d325a5d1fe85 100644 --- a/opossum/src/main.rs +++ b/opossum/src/main.rs @@ -79,13 +79,13 @@ fn create_report_and_data_files( let mut output = create_dot_or_report_file_instance( report_directory, &format!("report_{report_number}"), - "yaml", + "ron", "analysis report", )?; write!( output, "{}", - ron::ser::to_string_pretty(&report, ron::ser::PrettyConfig::default()).unwrap() + ron::ser::to_string_pretty(&report, ron::ser::PrettyConfig::new().new_line("\n")).unwrap() ) .map_err(|e| OpossumError::Other(format!("writing report file failed: {e}")))?; let mut report_path = report_directory.to_path_buf(); diff --git a/opossum/src/nodes/node_group/mod.rs b/opossum/src/nodes/node_group/mod.rs index eb72e85290e722cc0e1cbafcf0bdb99ce88cc366..765083f6846cb01de204ed74bae55b358d364b77 100644 --- a/opossum/src/nodes/node_group/mod.rs +++ b/opossum/src/nodes/node_group/mod.rs @@ -733,7 +733,10 @@ mod test { let mut scenery = NodeGroup::default(); scenery.add_node(Dummy::default()).unwrap(); let report = scenery.toplevel_report().unwrap(); - assert!(ron::ser::to_string_pretty(&report, ron::ser::PrettyConfig::default()).is_ok()); + assert!( + ron::ser::to_string_pretty(&report, ron::ser::PrettyConfig::new().new_line("\n")) + .is_ok() + ); // How shall we further parse the output? } #[test] diff --git a/opossum/src/nodes/node_group/optic_graph.rs b/opossum/src/nodes/node_group/optic_graph.rs index 772e6e9f475cf65ad114aa3874f63b39cd6fb5cc..f10186324083cf642b4659e7f9041f31cb02415e 100644 --- a/opossum/src/nodes/node_group/optic_graph.rs +++ b/opossum/src/nodes/node_group/optic_graph.rs @@ -1648,7 +1648,8 @@ mod test { vec!["input_1", "input_2"] ); let serialized = - ron::ser::to_string_pretty(&graph, ron::ser::PrettyConfig::default()).unwrap(); + ron::ser::to_string_pretty(&graph, ron::ser::PrettyConfig::new().new_line("\n")) + .unwrap(); let deserialized: OpticGraph = ron::from_str(&serialized).unwrap(); assert_eq!( deserialized.port_map(&PortType::Input).port_names(), diff --git a/opossum/src/nodes/source_helper.rs b/opossum/src/nodes/source_helper.rs index 72a5875ef07a8f99015bf09020a9a1f84d346f39..0e585f6777988bc795b2ff578b647708691a223c 100644 --- a/opossum/src/nodes/source_helper.rs +++ b/opossum/src/nodes/source_helper.rs @@ -2,12 +2,14 @@ //! Helper functions for easier creation of `standard` ray [`Source`]s. use super::Source; use crate::{ + energy_distributions::UniformDist, error::OpmResult, lightdata::{light_data_builder::LightDataBuilder, ray_data_builder::RayDataBuilder}, nanometer, optic_node::OpticNode, position_distributions::{Grid, Hexapolar}, rays::Rays, + spectral_distribution::LaserLines, utils::geom_transformation::Isometry, }; use nalgebra::Point3; @@ -29,12 +31,11 @@ pub fn round_collimated_ray_source( energy: Energy, nr_of_rings: u8, ) -> OpmResult<Source> { - let rays = Rays::new_uniform_collimated( - nanometer!(1000.0), - energy, - &Hexapolar::new(radius, nr_of_rings)?, - )?; - let light_data_builder = LightDataBuilder::Geometric(RayDataBuilder::Raw(rays)); + let light_data_builder = LightDataBuilder::Geometric(RayDataBuilder::Collimated { + pos_dist: Hexapolar::new(radius, nr_of_rings)?.into(), + energy_dist: UniformDist::new(energy)?.into(), + spect_dist: LaserLines::new(vec![(nanometer!(1000.0), 1.0)])?.into(), + }); let mut src = Source::new("collimated line ray source", light_data_builder); src.set_isometry(Isometry::identity())?; Ok(src) @@ -55,12 +56,11 @@ pub fn collimated_line_ray_source( energy: Energy, nr_of_points_y: usize, ) -> OpmResult<Source> { - let rays = Rays::new_uniform_collimated( - nanometer!(1000.0), - energy, - &Grid::new((Length::zero(), size_y), (1, nr_of_points_y))?, - )?; - let light_data_builder = LightDataBuilder::Geometric(RayDataBuilder::Raw(rays)); + let light_data_builder = LightDataBuilder::Geometric(RayDataBuilder::Collimated { + pos_dist: Grid::new((Length::zero(), size_y), (1, nr_of_points_y))?.into(), + energy_dist: UniformDist::new(energy)?.into(), + spect_dist: LaserLines::new(vec![(nanometer!(1000.0), 1.0)])?.into(), + }); let mut src = Source::new("collimated line ray source", light_data_builder); src.set_isometry(Isometry::identity())?; Ok(src) diff --git a/opossum/src/opm_document.rs b/opossum/src/opm_document.rs index 3eb361ee2e080c51e831ca88ee77335bc8b54ea9..049fa3bb86612fa1fdc1c3f891edf9ec4dc04238 100644 --- a/opossum/src/opm_document.rs +++ b/opossum/src/opm_document.rs @@ -126,9 +126,9 @@ impl OpmDocument { /// /// This function will return an error if the serialization of the internal structures fail. pub fn to_opm_file_string(&self) -> OpmResult<String> { - ron::ser::to_string_pretty(&self, ron::ser::PrettyConfig::default()).map_err(|e| { - OpossumError::OpticScenery(format!("serialization of OpmDocument failed: {e}")) - }) + ron::ser::to_string_pretty(&self, ron::ser::PrettyConfig::new().new_line("\n")).map_err( + |e| OpossumError::OpticScenery(format!("serialization of OpmDocument failed: {e}")), + ) } /// Returns the list of analyzers of this [`OpmDocument`]. #[must_use] diff --git a/opossum/src/optic_ref.rs b/opossum/src/optic_ref.rs index 70d89d45de6b798289ab588089a671c5bc94ab7f..96a6c68dfac1fdeb4753355fb93691ed32dc8950 100644 --- a/opossum/src/optic_ref.rs +++ b/opossum/src/optic_ref.rs @@ -224,7 +224,9 @@ mod test { #[test] fn serialize() { let optic_ref = OpticRef::new(Arc::new(Mutex::new(Dummy::default())), None); - let _ = ron::ser::to_string_pretty(&optic_ref, ron::ser::PrettyConfig::default()).unwrap(); + let _ = + ron::ser::to_string_pretty(&optic_ref, ron::ser::PrettyConfig::new().new_line("\n")) + .unwrap(); } #[test] fn deserialize() { diff --git a/opossum/src/position_distributions/fibonacci.rs b/opossum/src/position_distributions/fibonacci.rs index a44b72fe101624ff8406839a6ae27adb0fb40a61..cb45fc9b370835a4227b24d9beaac0d2eadb541b 100644 --- a/opossum/src/position_distributions/fibonacci.rs +++ b/opossum/src/position_distributions/fibonacci.rs @@ -7,11 +7,13 @@ use crate::error::{OpmResult, OpossumError}; use super::PositionDistribution; use nalgebra::{point, Point3}; use num::{ToPrimitive, Zero}; +use serde::{Deserialize, Serialize}; use uom::si::f64::Length; /// Rectangular Fibonacci distribution /// /// For further details see [here](https://en.wikipedia.org/wiki/Fibonacci_sequence) +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct FibonacciRectangle { nr_of_rays: usize, side_length_x: Length, @@ -62,11 +64,15 @@ impl PositionDistribution for FibonacciRectangle { points } } - +impl From<FibonacciRectangle> for super::PosDistType { + fn from(f: FibonacciRectangle) -> Self { + Self::FibonacciRectangle(f) + } +} /// Rectangular Fibbonacci distribution /// /// For further details see [here](https://en.wikipedia.org/wiki/Fibonacci_sequence) -#[derive(Clone)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct FibonacciEllipse { nr_of_rays: usize, radius_x: Length, @@ -119,7 +125,11 @@ impl PositionDistribution for FibonacciEllipse { points } } - +impl From<FibonacciEllipse> for super::PosDistType { + fn from(f: FibonacciEllipse) -> Self { + Self::FibonacciEllipse(f) + } +} #[cfg(test)] mod test { use super::*; diff --git a/opossum/src/position_distributions/grid.rs b/opossum/src/position_distributions/grid.rs index 2bda4bebb712e4733c8e7661f8616b8f8b59e9cf..0ef7445785d46d83e8952245bc6bba2097949587 100644 --- a/opossum/src/position_distributions/grid.rs +++ b/opossum/src/position_distributions/grid.rs @@ -7,10 +7,11 @@ use crate::{ }; use nalgebra::Point3; use num::Zero; +use serde::{Deserialize, Serialize}; use uom::si::f64::Length; /// Rectangular, evenly-sized grid distribution -#[derive(Clone)] +#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)] pub struct Grid { nr_of_points: (usize, usize), side_length: (Length, Length), @@ -91,6 +92,11 @@ impl PositionDistribution for Grid { } } +impl From<Grid> for super::PosDistType { + fn from(grid: Grid) -> Self { + Self::Grid(grid) + } +} #[cfg(test)] mod test { use super::*; diff --git a/opossum/src/position_distributions/hexagonal_tiling.rs b/opossum/src/position_distributions/hexagonal_tiling.rs index a6499eeb5117d7fb606b3ad8e5e75227c3ffc7a7..3fccec786df861d4912c2c0d8894520dcda05e9d 100644 --- a/opossum/src/position_distributions/hexagonal_tiling.rs +++ b/opossum/src/position_distributions/hexagonal_tiling.rs @@ -9,10 +9,11 @@ use crate::{ use super::PositionDistribution; use nalgebra::{Point2, Point3, Vector3}; use num::{ToPrimitive, Zero}; +use serde::{Deserialize, Serialize}; use uom::si::f64::Length; /// Circular, hexapolar distribution -#[derive(Clone)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct HexagonalTiling { nr_of_hex_along_radius: u8, radius: Length, @@ -93,25 +94,10 @@ impl PositionDistribution for HexagonalTiling { } points } - // fn generate(&self) -> Vec<Point3<Length>> { - // let mut points: Vec<Point3<Length>> = Vec::new(); - // // Add center point - // points.push(Point3::origin()); +} - // let radius_step = self.radius/self.nr_of_hex_along_radius.to_f64().unwrap(); - // for i in 1_u8..self.nr_of_hex_along_radius+1{ - // // let mut last_point = points.last().unwrap().clone(); - // // last_point.x += radius_step; - // let mut hex = Point3::origin(); - // hex.x += radius_step*i.to_f64().unwrap(); - // for j in 0_u8..6{ - // for k in 0_u8..i{ - // points.push(hex); - // let angle = PI/3.*(2.+j.to_f64().unwrap()); - // hex = hex + Vector3::new(f64::cos(angle)*radius_step, f64::sin(angle)*radius_step,Length::zero()); - // } - // } - // } - // points - // } +impl From<HexagonalTiling> for super::PosDistType { + fn from(hexagonal_tiling: HexagonalTiling) -> Self { + Self::HexagonalTiling(hexagonal_tiling) + } } diff --git a/opossum/src/position_distributions/hexapolar.rs b/opossum/src/position_distributions/hexapolar.rs index 5b7214b0b32e0aafc9a74d8a9830c2a50bbfa032..95e64928871affad87b20b0efb925203f68d9c94 100644 --- a/opossum/src/position_distributions/hexapolar.rs +++ b/opossum/src/position_distributions/hexapolar.rs @@ -4,10 +4,11 @@ use crate::error::{OpmResult, OpossumError}; use super::PositionDistribution; use nalgebra::{point, Point3}; use num::Zero; +use serde::{Deserialize, Serialize}; use uom::si::f64::Length; /// Circular, hexapolar distribution -#[derive(Clone)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct Hexapolar { nr_of_rings: u8, radius: Length, @@ -54,6 +55,11 @@ impl PositionDistribution for Hexapolar { points } } +impl From<Hexapolar> for super::PosDistType { + fn from(dist: Hexapolar) -> Self { + Self::Hexapolar(dist) + } +} #[cfg(test)] mod test { use super::*; diff --git a/opossum/src/position_distributions/mod.rs b/opossum/src/position_distributions/mod.rs index 4a44bdbf5e06b1df04e2dc813528449b2acbc1cf..097ff23dfca710cd3d927a6f3f8cb4b6291c190f 100644 --- a/opossum/src/position_distributions/mod.rs +++ b/opossum/src/position_distributions/mod.rs @@ -17,6 +17,7 @@ //! ``` //! `points` now contains a vector of 10 randomly-placed 3D points within the rectangle (-0.5 mm .. 0.5 mm) x (-1.0 mm .. 1.0 mm). use nalgebra::Point3; +use serde::{Deserialize, Serialize}; use uom::si::f64::Length; mod fibonacci; @@ -40,3 +41,37 @@ pub trait PositionDistribution { /// This function generates a vector of 3D points (of dimension [`Length`]) with the given parameters defined earlier. fn generate(&self) -> Vec<Point3<Length>>; } + +/// Enum for the different types of position distributions +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub enum PosDistType { + /// Rectangular, uniform random distribution + Random(random::Random), + /// Rectangular, evenly-sized grid distribution + Grid(grid::Grid), + /// Hexagonal tiling distribution + HexagonalTiling(hexagonal_tiling::HexagonalTiling), + /// Hexapolar distribution + Hexapolar(hexapolar::Hexapolar), + /// Fibonacci rectangle distribution + FibonacciRectangle(fibonacci::FibonacciRectangle), + /// Fibonacci ellipse distribution + FibonacciEllipse(fibonacci::FibonacciEllipse), + /// Pseudo random Sobol distribution + Sobol(sobol::SobolDist), +} +impl PosDistType { + /// Generate the point distribution. + #[must_use] + pub fn generate(&self) -> &dyn PositionDistribution { + match self { + Self::Random(dist) => dist, + Self::Grid(dist) => dist, + Self::HexagonalTiling(dist) => dist, + Self::Hexapolar(dist) => dist, + Self::FibonacciRectangle(dist) => dist, + Self::FibonacciEllipse(dist) => dist, + Self::Sobol(dist) => dist, + } + } +} diff --git a/opossum/src/position_distributions/random.rs b/opossum/src/position_distributions/random.rs index 96f4163f13a449d621fc13fca536edc8ee53f3a0..b51661eb0ad091dc50e8e994249b122b9299014b 100644 --- a/opossum/src/position_distributions/random.rs +++ b/opossum/src/position_distributions/random.rs @@ -5,9 +5,11 @@ use crate::error::{OpmResult, OpossumError}; use nalgebra::{point, Point3}; use num::Zero; use rand::Rng; +use serde::{Deserialize, Serialize}; use uom::si::f64::Length; /// Rectangular, uniform random distribution +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct Random { nr_of_points: usize, side_length_x: Length, @@ -64,6 +66,11 @@ impl PositionDistribution for Random { points } } +impl From<Random> for super::PosDistType { + fn from(random: Random) -> Self { + Self::Random(random) + } +} #[cfg(test)] mod test { use super::*; diff --git a/opossum/src/position_distributions/sobol.rs b/opossum/src/position_distributions/sobol.rs index c164006ddc101011be7aa747a3f2a761f8c81b8a..bbcf8fa385438e50aac1d2f61090d379cd9fb0da 100644 --- a/opossum/src/position_distributions/sobol.rs +++ b/opossum/src/position_distributions/sobol.rs @@ -3,12 +3,14 @@ use super::PositionDistribution; use crate::error::{OpmResult, OpossumError}; use nalgebra::{point, Point3}; use num::Zero; +use serde::{Deserialize, Serialize}; use sobol::{params::JoeKuoD6, Sobol}; use uom::si::f64::Length; /// Rectangluar, low-discrepancy quasirandom distribution /// /// For further details see [here](https://en.wikipedia.org/wiki/Sobol_sequence) +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct SobolDist { nr_of_points: usize, side_length_x: Length, @@ -68,6 +70,11 @@ impl PositionDistribution for SobolDist { points } } +impl From<SobolDist> for super::PosDistType { + fn from(f: SobolDist) -> Self { + Self::Sobol(f) + } +} #[cfg(test)] mod test { use super::*; diff --git a/opossum/src/refractive_index/refr_index_conrady.rs b/opossum/src/refractive_index/refr_index_conrady.rs index 4c6859e006d4eeda0c815637248b8106147e1268..915ed5a3bef1215a0e5f378eaff12070d36f434a 100644 --- a/opossum/src/refractive_index/refr_index_conrady.rs +++ b/opossum/src/refractive_index/refr_index_conrady.rs @@ -65,6 +65,11 @@ impl RefractiveIndex for RefrIndexConrady { RefractiveIndexType::Conrady(self.clone()) } } +impl From<RefrIndexConrady> for RefractiveIndexType { + fn from(refr: RefrIndexConrady) -> Self { + Self::Conrady(refr) + } +} #[cfg(test)] mod test { use super::*; diff --git a/opossum/src/refractive_index/refr_index_const.rs b/opossum/src/refractive_index/refr_index_const.rs index 5f999e249ed1380a6d12b417c8a9a5e6e8f5e98e..f20a55730d084a7ee581777bc82c5be17060ac55 100644 --- a/opossum/src/refractive_index/refr_index_const.rs +++ b/opossum/src/refractive_index/refr_index_const.rs @@ -46,7 +46,11 @@ impl RefractiveIndex for RefrIndexConst { RefractiveIndexType::Const(self.clone()) } } - +impl From<RefrIndexConst> for RefractiveIndexType { + fn from(i: RefrIndexConst) -> Self { + Self::Const(i) + } +} #[cfg(test)] mod test { use num::Zero; diff --git a/opossum/src/refractive_index/refr_index_schott.rs b/opossum/src/refractive_index/refr_index_schott.rs index 888fedd2ca0b78ab3c20c57875470148046b6a02..19a6780eca75092e740e153f7df1878f850955d7 100644 --- a/opossum/src/refractive_index/refr_index_schott.rs +++ b/opossum/src/refractive_index/refr_index_schott.rs @@ -93,6 +93,11 @@ impl RefractiveIndex for RefrIndexSchott { RefractiveIndexType::Schott(self.clone()) } } +impl From<RefrIndexSchott> for RefractiveIndexType { + fn from(refr: RefrIndexSchott) -> Self { + Self::Schott(refr) + } +} #[cfg(test)] mod test { use super::*; diff --git a/opossum/src/refractive_index/refr_index_sellmeier1.rs b/opossum/src/refractive_index/refr_index_sellmeier1.rs index 8f1d995528ba6fa781982526da4ef520643bd754..85f250a4e3c39d1109e00de605cd7b79f2288ef8 100644 --- a/opossum/src/refractive_index/refr_index_sellmeier1.rs +++ b/opossum/src/refractive_index/refr_index_sellmeier1.rs @@ -91,6 +91,11 @@ impl RefractiveIndex for RefrIndexSellmeier1 { RefractiveIndexType::Sellmeier1(self.clone()) } } +impl From<RefrIndexSellmeier1> for RefractiveIndexType { + fn from(refr: RefrIndexSellmeier1) -> Self { + Self::Sellmeier1(refr) + } +} #[cfg(test)] mod test { use crate::nanometer; diff --git a/opossum/src/spectral_distribution/gaussian.rs b/opossum/src/spectral_distribution/gaussian.rs index 962ed775b81524a9143d3b10b8aa846a310f3ec8..5fcf12551036462a65612b47c2cfcc9d92c7f021 100644 --- a/opossum/src/spectral_distribution/gaussian.rs +++ b/opossum/src/spectral_distribution/gaussian.rs @@ -1,3 +1,4 @@ +use serde::{Deserialize, Serialize}; use uom::si::f64::Length; use super::SpectralDistribution; @@ -8,6 +9,7 @@ use crate::utils::math_distribution_functions::gaussian; use itertools::Itertools; use kahan::KahanSummator; +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Gaussian { wvl_range: (Length, Length), num_points: usize, @@ -94,6 +96,11 @@ impl SpectralDistribution for Gaussian { .collect_vec()) } } +impl From<Gaussian> for super::SpecDistType { + fn from(g: Gaussian) -> Self { + Self::Gaussian(g) + } +} #[cfg(test)] mod test { use crate::{ diff --git a/opossum/src/spectral_distribution/laser_lines.rs b/opossum/src/spectral_distribution/laser_lines.rs new file mode 100644 index 0000000000000000000000000000000000000000..5654173ad1b4bf1878327112bc36df884fedbea6 --- /dev/null +++ b/opossum/src/spectral_distribution/laser_lines.rs @@ -0,0 +1,74 @@ +use serde::{Deserialize, Serialize}; +use uom::si::f64::Length; + +use crate::error::{OpmResult, OpossumError}; + +use super::SpectralDistribution; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +/// A struct representing a collection of laser lines with their respective wavelengths and relative intensities. +pub struct LaserLines { + lines: Vec<(Length, f64)>, +} +impl LaserLines { + /// Creates a new `LaserLines` instance with the given laser lines. + /// + /// The given intensities are normalized to sum to 1.0. + /// + /// # Arguments + /// + /// * `lines` - A vector of tuples containing the wavelength and intensity of each laser line. + /// + /// # Errors + /// + /// This function returns an error if + /// * the vector is empty, + /// * any wavelength is negative or infinite, + /// * any intensity is negative or infinite, + /// * the sum of intensities is zero. + pub fn new(lines: Vec<(Length, f64)>) -> OpmResult<Self> { + // Check if the lines are non-empty and contain valid data + if lines.is_empty() { + return Err(OpossumError::Other("Laser lines cannot be empty".into())); + } + for (wavelength, intensity) in &lines { + if !wavelength.is_normal() || wavelength.is_sign_negative() { + return Err(OpossumError::Other( + "Wavelength must be positive and finite".into(), + )); + } + if !intensity.is_normal() || intensity.is_sign_negative() { + return Err(OpossumError::Other( + "Intensity must be positive and finite".into(), + )); + } + } + // Normalize the intensities to sum to 1.0 + let sum_intensity: f64 = lines.iter().map(|(_, intensity)| *intensity).sum(); + if sum_intensity == 0.0 { + return Err(OpossumError::Other( + "Sum of intensities cannot be zero".into(), + )); + } + let lines: Vec<(Length, f64)> = lines + .into_iter() + .map(|(wavelength, intensity)| (wavelength, intensity / sum_intensity)) + .collect(); + Ok(Self { lines }) + } +} +impl SpectralDistribution for LaserLines { + /// Generates the laser lines. + /// + /// # Returns + /// + /// A vector of tuples containing the wavelength and intensity of each laser line. + fn generate(&self) -> OpmResult<Vec<(Length, f64)>> { + Ok(self.lines.clone()) + } +} +impl From<LaserLines> for super::SpecDistType { + fn from(laser_lines: LaserLines) -> Self { + Self::LaserLines(laser_lines) + } +} diff --git a/opossum/src/spectral_distribution/mod.rs b/opossum/src/spectral_distribution/mod.rs index 1b85595049428e4f4a900e05739c521ddb296bde..10ad43232a14743118ca4f78b4a5626bfc16aa93 100644 --- a/opossum/src/spectral_distribution/mod.rs +++ b/opossum/src/spectral_distribution/mod.rs @@ -1,9 +1,12 @@ //! Module for handling spectral distributions use crate::error::OpmResult; +use serde::{Deserialize, Serialize}; use uom::si::f64::Length; pub mod gaussian; +pub mod laser_lines; pub use gaussian::Gaussian; +pub use laser_lines::LaserLines; pub trait SpectralDistribution { /// Creates a Gaussian spectral distribution @@ -11,3 +14,22 @@ pub trait SpectralDistribution { /// This function only propagates errors of the contained functions fn generate(&self) -> OpmResult<Vec<(Length, f64)>>; } + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +/// Enum representing different types of spectral distributions +pub enum SpecDistType { + Gaussian(gaussian::Gaussian), + LaserLines(laser_lines::LaserLines), +} +impl SpecDistType { + /// Generates the spectral distribution + /// # Errors + /// This function only propagates errors of the contained functions + #[must_use] + pub fn generate(&self) -> &dyn SpectralDistribution { + match self { + Self::Gaussian(g) => g, + Self::LaserLines(l) => l, + } + } +} diff --git a/opossum/src/spectrum.rs b/opossum/src/spectrum.rs index c2cc3231d6379d584ac2d784957619c64034dbb7..78d295937f841ee2ec2800705f1795f684aa15ef 100644 --- a/opossum/src/spectrum.rs +++ b/opossum/src/spectrum.rs @@ -999,10 +999,10 @@ mod test { #[test] fn serialize() { let s = prep(); - let s_yaml = ron::ser::to_string_pretty(&s, ron::ser::PrettyConfig::default()); - assert!(s_yaml.is_ok()); - assert_eq!(s_yaml.unwrap(), - "(\r\n data: [\r\n (1.0, 0.0),\r\n (1.5, 0.0),\r\n (2.0, 0.0),\r\n (2.5, 0.0),\r\n (3.0, 0.0),\r\n (3.5, 0.0),\r\n ],\r\n)".to_string()); + let s_ron = + ron::ser::to_string_pretty(&s, ron::ser::PrettyConfig::new().new_line("\n")).unwrap(); + assert_eq!(s_ron, + "(\n data: [\n (1.0, 0.0),\n (1.5, 0.0),\n (2.0, 0.0),\n (2.5, 0.0),\n (3.0, 0.0),\n (3.5, 0.0),\n ],\n)".to_string()); } #[test] fn deserialize() {