From 3a5ede11a75578744f6e6f2d87449ba443156a5a Mon Sep 17 00:00:00 2001
From: Udo Eisenbarth <udo.eisenbarth@web.de>
Date: Mon, 10 Jul 2023 16:16:13 +0200
Subject: [PATCH] Add Spectrum structure and a first example

---
 examples/source_detector_test.rs |  4 +--
 examples/spectrum_test.rs        | 10 ++++++
 src/lib.rs                       |  4 ++-
 src/lightdata.rs                 |  8 ++---
 src/nodes/ideal_filter.rs        |  4 +--
 src/nodes/node_beam_splitter.rs  |  6 ++--
 src/spectrum.rs                  | 52 ++++++++++++++++++++++++++++++++
 7 files changed, 76 insertions(+), 12 deletions(-)
 create mode 100644 examples/spectrum_test.rs
 create mode 100644 src/spectrum.rs

diff --git a/examples/source_detector_test.rs b/examples/source_detector_test.rs
index 72618307..cee7df72 100644
--- a/examples/source_detector_test.rs
+++ b/examples/source_detector_test.rs
@@ -3,7 +3,7 @@ use std::io::Write;
 use uom::si::{f64::Energy, energy::joule};
 
 use opossum::{
-    lightdata::{LightData, LightDataEnergy},
+    lightdata::{LightData, DataEnergy},
     nodes::{Detector, Source, BeamSplitter, IdealFilter},
     optic_scenery::OpticScenery, analyzer::AnalyzerEnergy,
 };
@@ -14,7 +14,7 @@ fn main() {
 
     let i_s = scenery.add_element(
         "Source",
-        Source::new(LightData::Energy(LightDataEnergy { energy: Energy::new::<joule>(1.0) })),
+        Source::new(LightData::Energy(DataEnergy { energy: Energy::new::<joule>(1.0) })),
     );
     let i_bs=scenery.add_element("Beam splitter", BeamSplitter::new(0.6));
     let i_f=scenery.add_element("Filter", IdealFilter::new(0.5).unwrap());
diff --git a/examples/spectrum_test.rs b/examples/spectrum_test.rs
new file mode 100644
index 00000000..f6dd9cea
--- /dev/null
+++ b/examples/spectrum_test.rs
@@ -0,0 +1,10 @@
+use opossum::spectrum::Spectrum;
+use uom::si::energy::joule;
+use uom::si::{f64::Length, length::nanometer};
+use uom::si::f64::Energy;
+
+fn main() {
+    let mut s=Spectrum::new(Length::new::<nanometer>(400.0)..Length::new::<nanometer>(410.0),Length::new::<nanometer>(1.0));
+    s.set_single_peak(Length::new::<nanometer>(405.0), Energy::new::<joule>(1.0));
+    println!("{}",s);
+}
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index 1fff6d42..ed4f674f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -13,4 +13,6 @@ pub mod nodes;
 
 pub mod analyzer;
 
-pub mod error;
\ No newline at end of file
+pub mod error;
+
+pub mod spectrum;
\ No newline at end of file
diff --git a/src/lightdata.rs b/src/lightdata.rs
index be516021..b2ebfa4a 100644
--- a/src/lightdata.rs
+++ b/src/lightdata.rs
@@ -4,8 +4,8 @@ use uom::fmt::DisplayStyle::Abbreviation;
 
 #[derive(Debug, PartialEq, Clone)]
 pub enum LightData {
-    Energy(LightDataEnergy),
-    Geometric(LightDataGeometric),
+    Energy(DataEnergy),
+    Geometric(DataGeometric),
     Fourier,
 }
 
@@ -22,11 +22,11 @@ impl Display for LightData {
     }
 }
 #[derive(Debug, PartialEq, Clone)]
-pub struct LightDataEnergy {
+pub struct DataEnergy {
     pub energy: Energy,
 }
 
 #[derive(Debug, PartialEq, Clone)]
-pub struct LightDataGeometric {
+pub struct DataGeometric {
     ray: i32,
 }
diff --git a/src/nodes/ideal_filter.rs b/src/nodes/ideal_filter.rs
index 733d0a94..e7378cf5 100644
--- a/src/nodes/ideal_filter.rs
+++ b/src/nodes/ideal_filter.rs
@@ -1,6 +1,6 @@
 use crate::analyzer::AnalyzerType;
 use crate::error::OpossumError;
-use crate::lightdata::{LightData, LightDataEnergy};
+use crate::lightdata::{LightData, DataEnergy};
 use crate::optic_node::{Dottable, LightResult, Optical};
 use crate::optic_ports::OpticPorts;
 use std::collections::HashMap;
@@ -73,7 +73,7 @@ impl IdealFilter {
                 _ => return Err(OpossumError::Analysis("expected energy value".into())),
             }
         }
-        let output_energy = Some(LightData::Energy(LightDataEnergy {
+        let output_energy = Some(LightData::Energy(DataEnergy {
             energy: input_energy * self.transmission,
         }));
         Ok(HashMap::from([("rear".into(), output_energy)]))
diff --git a/src/nodes/node_beam_splitter.rs b/src/nodes/node_beam_splitter.rs
index 344e09f1..bd1f60c6 100644
--- a/src/nodes/node_beam_splitter.rs
+++ b/src/nodes/node_beam_splitter.rs
@@ -4,7 +4,7 @@ use uom::{si::f64::Energy, num_traits::Zero};
 use crate::{
     analyzer::AnalyzerType,
     error::OpossumError,
-    lightdata::{LightData, LightDataEnergy},
+    lightdata::{LightData, DataEnergy},
     optic_node::{Dottable, LightResult, Optical},
     optic_ports::OpticPorts,
 };
@@ -51,10 +51,10 @@ impl BeamSplitter {
                 _ => return Err(OpossumError::Analysis("expected energy value".into())),
             }
         }
-        let out1_energy = Some(LightData::Energy(LightDataEnergy {
+        let out1_energy = Some(LightData::Energy(DataEnergy {
             energy: in1_energy * self.ratio + in2_energy * (1.0 - self.ratio),
         }));
-        let out2_energy = Some(LightData::Energy(LightDataEnergy {
+        let out2_energy = Some(LightData::Energy(DataEnergy {
             energy: in1_energy * (1.0 - self.ratio) + in2_energy * self.ratio,
         }));
         Ok(HashMap::from([
diff --git a/src/spectrum.rs b/src/spectrum.rs
new file mode 100644
index 00000000..826dd05d
--- /dev/null
+++ b/src/spectrum.rs
@@ -0,0 +1,52 @@
+use std::fmt::Display;
+use std::ops::Range;
+use uom::fmt::DisplayStyle::Abbreviation;
+use uom::num_traits::Zero;
+use uom::si::energy::joule;
+use uom::si::{
+    f64::{Energy, Length},
+    length::nanometer,
+};
+pub struct Spectrum {
+    start: Length,
+    dlambda: Length,
+    data: Vec<Energy>,
+}
+
+impl Spectrum {
+    pub fn new(range: Range<Length>, resolution: Length) -> Self {
+        Self {
+            start: range.start,
+            dlambda: resolution,
+            data: vec![Energy::zero(); ((range.end-range.start)/resolution).value as usize]
+        }
+    }
+    pub fn set_single_peak(&mut self, wavelength: Length, energy: Energy) {
+        let index=((wavelength-self.start) / self.dlambda).value as usize;
+        self.data[index]=energy; 
+    }
+    pub fn total_energy(&self) -> Energy {
+        let mut total_energy=Energy::zero();
+        for data in self.data.iter() {
+            total_energy+=*data;
+        }
+        total_energy
+    }
+}
+
+impl Display for Spectrum {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let fmt_length = Length::format_args(nanometer, Abbreviation);
+        let fmt_energy = Energy::format_args(joule, Abbreviation);
+        for value in self.data.iter().enumerate() {
+            let wavelength=self.start + value.0 as f64 * self.dlambda;
+            write!(
+                f,
+                "{:7.2} -> {}\n",
+                fmt_length.with(wavelength),
+                fmt_energy.with(*value.1)
+            ).unwrap();
+        }
+        write!(f, "\nTotal energy: {}",fmt_energy.with(self.total_energy()))
+    }
+}
-- 
GitLab