Skip to content
Snippets Groups Projects
beam_splitter.rs 4.23 KiB
Newer Older
Udo Eisenbarth's avatar
Udo Eisenbarth committed
#![warn(missing_docs)]
use std::collections::HashMap;

Udo Eisenbarth's avatar
Udo Eisenbarth committed
use crate::{
    analyzer::AnalyzerType,
    error::OpossumError,
    lightdata::{DataEnergy, LightData},
    optic_node::{Dottable, LightResult, Optical},
    optic_ports::OpticPorts,
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    spectrum::{merge_spectra, Spectrum},
Udo Eisenbarth's avatar
Udo Eisenbarth committed
};
type Result<T> = std::result::Result<T, OpossumError>;

Udo Eisenbarth's avatar
Udo Eisenbarth committed
/// An ideal beamsplitter node with a given splitting ratio.
Udo Eisenbarth's avatar
Udo Eisenbarth committed
///
/// ## Optical Ports
///   - Inputs
///     - `input1`
///     - `input2`
///   - Outputs
///     - `out1_trans1_refl2`
///     - `out2_trans2_refl1`
Udo Eisenbarth's avatar
Udo Eisenbarth committed
pub struct BeamSplitter {
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    ratio: f64,
Udo Eisenbarth's avatar
Udo Eisenbarth committed
}

Udo Eisenbarth's avatar
Udo Eisenbarth committed
impl BeamSplitter {
    /// Creates a new [`BeamSplitter`] with a given splitting ratio.
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    pub fn new(ratio: f64) -> Self {
Udo Eisenbarth's avatar
Udo Eisenbarth committed
        Self { ratio }
    }

Udo Eisenbarth's avatar
Udo Eisenbarth committed
    /// Returns the splitting ratio of this [`BeamSplitter`].
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    pub fn ratio(&self) -> f64 {
Udo Eisenbarth's avatar
Udo Eisenbarth committed
        self.ratio
    }
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    /// Sets the splitting ratio of this [`BeamSplitter`].
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    pub fn set_ratio(&mut self, ratio: f64) {
Udo Eisenbarth's avatar
Udo Eisenbarth committed
        self.ratio = ratio;
    }
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    fn analyze_energy(&mut self, incoming_data: LightResult) -> Result<LightResult> {
        let in1 = incoming_data.get("input1");
        let in2 = incoming_data.get("input2");
        let mut out1_1_spectrum: Option<Spectrum> = None;
        let mut out1_2_spectrum: Option<Spectrum> = None;
        let mut out2_1_spectrum: Option<Spectrum> = None;
        let mut out2_2_spectrum: Option<Spectrum> = None;
        if let Some(Some(in1)) = in1 {
            match in1 {
                LightData::Energy(e) => {
                    let mut s = e.spectrum.clone();
                    s.scale_vertical(self.ratio).unwrap();
                    out1_1_spectrum = Some(s);
                    let mut s = e.spectrum.clone();
                    s.scale_vertical(1.0 - self.ratio).unwrap();
                    out1_2_spectrum = Some(s);
                _ => return Err(OpossumError::Analysis("expected DataEnergy value".into())),
        if let Some(Some(in2)) = in2 {
            match in2 {
                LightData::Energy(e) => {
                    let mut s = e.spectrum.clone();
                    s.scale_vertical(self.ratio).unwrap();
                    out2_1_spectrum = Some(s);
                    let mut s = e.spectrum.clone();
                    s.scale_vertical(1.0 - self.ratio).unwrap();
                    out2_2_spectrum = Some(s);
                }
                _ => return Err(OpossumError::Analysis("expected DataEnergy value".into())),
Udo Eisenbarth's avatar
Udo Eisenbarth committed
        let out1_spec = merge_spectra(out1_1_spectrum, out2_2_spectrum);
        let out2_spec = merge_spectra(out1_2_spectrum, out2_1_spectrum);
        let mut out1_data: Option<LightData> = None;
        let mut out2_data: Option<LightData> = None;
        if let Some(out1_spec) = out1_spec {
            out1_data = Some(LightData::Energy(DataEnergy {
                spectrum: out1_spec,
            }))
        if let Some(out2_spec) = out2_spec {
            out2_data = Some(LightData::Energy(DataEnergy {
                spectrum: out2_spec,
            }))
        Ok(HashMap::from([
            ("out1_trans1_refl2".into(), out1_data),
            ("out2_trans2_refl1".into(), out2_data),
Udo Eisenbarth's avatar
Udo Eisenbarth committed
}

Udo Eisenbarth's avatar
Udo Eisenbarth committed
impl Default for BeamSplitter {
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    /// Create a 50:50 beamsplitter.
    fn default() -> Self {
        Self { ratio: 0.5 }
    }
}
Udo Eisenbarth's avatar
Udo Eisenbarth committed
impl Optical for BeamSplitter {
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    fn node_type(&self) -> &str {
        "ideal beam splitter"
    }
    fn ports(&self) -> OpticPorts {
        let mut ports = OpticPorts::new();
        ports.add_input("input1").unwrap();
        ports.add_input("input2").unwrap();
        ports.add_output("out1_trans1_refl2").unwrap();
        ports.add_output("out2_trans2_refl1").unwrap();
        ports
    }

    fn analyze(
        &mut self,
        incoming_data: LightResult,
        analyzer_type: &AnalyzerType,
    ) -> Result<LightResult> {
        match analyzer_type {
            AnalyzerType::Energy => self.analyze_energy(incoming_data),
            _ => Err(OpossumError::Analysis(
                "analysis type not yet implemented".into(),
            )),
Udo Eisenbarth's avatar
Udo Eisenbarth committed
impl Dottable for BeamSplitter {
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    fn node_color(&self) -> &str {
        "lightpink"
    }