Skip to content
Snippets Groups Projects
detector.rs 6.27 KiB
Newer Older
Udo Eisenbarth's avatar
Udo Eisenbarth committed
#![warn(missing_docs)]
Udo Eisenbarth's avatar
Udo Eisenbarth committed
use crate::error::OpmResult;
use crate::lightdata::LightData;
use crate::properties::{Properties, Property, Proptype};
    dottable::Dottable,
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    error::OpossumError,
    optic_ports::OpticPorts,
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    optical::{LightResult, Optical},
use std::collections::HashMap;
use std::fmt::Debug;
/// This node represents an universal detector (so far for test / debugging purposes).
/// Any [`LightData`] coming in will be stored internally for later display / export.
Udo Eisenbarth's avatar
Udo Eisenbarth committed
///
/// ## Optical Ports
///   - Inputs
///     - `in1`
///   - Outputs
///     - `out1`
Udo Eisenbarth's avatar
Udo Eisenbarth committed
///
/// ## Properties
///   - `name`
///   - `inverted`
///
Udo Eisenbarth's avatar
Udo Eisenbarth committed
/// During analysis, the output port contains a replica of the input port similar to a [`Dummy`](crate::nodes::Dummy) node. This way,
/// different dectector nodes can be "stacked" or used somewhere in between arbitrary optic nodes.
Udo Eisenbarth's avatar
Udo Eisenbarth committed
pub struct Detector {
    light_data: Option<LightData>,
    props: Properties,
}
fn create_default_props() -> Properties {
    let mut props = Properties::default();
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    props.set("name", "detector".into());
    props.set("inverted", false.into());
    props
}
impl Default for Detector {
    fn default() -> Self {
        Self {
            light_data: Default::default(),
            props: create_default_props(),
        }
impl Detector {
    /// Creates a new [`Detector`].
    pub fn new(name: &str) -> Self {
        let mut props = create_default_props();
        props.set("name", name.into());
        Self {
            props,
            ..Default::default()
        }
    }
}
Udo Eisenbarth's avatar
Udo Eisenbarth committed
impl Optical for Detector {
    fn name(&self) -> &str {
        if let Some(value) = self.props.get("name") {
            if let Proptype::String(name) = &value.prop {
                return name;
            }
        }
        panic!("wrong format");
    }
    fn inverted(&self) -> bool {
        self.properties().get_bool("inverted").unwrap().unwrap()
    }
    fn node_type(&self) -> &str {
    }
    fn ports(&self) -> OpticPorts {
        let mut ports = OpticPorts::new();
        ports.add_input("in1").unwrap();
        ports.add_output("out1").unwrap();
        ports
    }
    fn analyze(
        &mut self,
        incoming_data: LightResult,
        _analyzer_type: &crate::analyzer::AnalyzerType,
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    ) -> OpmResult<LightResult> {
        if !self.inverted() {
            let data = incoming_data.get("in1").unwrap_or(&None);
            Ok(HashMap::from([("out1".into(), data.clone())]))
        } else {
            let data = incoming_data.get("out1").unwrap_or(&None);
            Ok(HashMap::from([("in1".into(), data.clone())]))
    fn is_detector(&self) -> bool {
        true
    }
    fn properties(&self) -> &Properties {
        &self.props
    }
Udo Eisenbarth's avatar
Udo Eisenbarth committed
    fn set_property(&mut self, name: &str, prop: Property) -> OpmResult<()> {
        if self.props.set(name, prop).is_none() {
            Err(OpossumError::Other("property not defined".into()))
        } else {
            Ok(())
        }
    }
Udo Eisenbarth's avatar
Udo Eisenbarth committed
impl Debug for Detector {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match &self.light_data {
            Some(data) => write!(f, "{}", data),
            None => write!(f, "no data"),
        }
    }
}
Udo Eisenbarth's avatar
Udo Eisenbarth committed
impl Dottable for Detector {
    fn node_color(&self) -> &str {
        "lemonchiffon"
#[cfg(test)]
mod test {
    use crate::{analyzer::AnalyzerType, lightdata::DataEnergy, spectrum::create_he_ne_spectrum};

    use super::*;
    #[test]
    fn default() {
        let node = Detector::default();
        assert_eq!(node.name(), "detector");
        assert_eq!(node.node_type(), "detector");
        assert_eq!(node.is_detector(), true);
        assert_eq!(node.inverted(), false);
        assert_eq!(node.node_color(), "lemonchiffon");
        assert!(node.as_group().is_err());
    }
    #[test]
    fn new() {
        let node = Detector::new("test");
        assert_eq!(node.name(), "test");
    }
    #[test]
    fn inverted() {
        let mut node = Detector::default();
        node.set_property("inverted", true.into()).unwrap();
        assert_eq!(node.inverted(), true)
    }
    #[test]
    fn ports() {
        let node = Detector::default();
        assert_eq!(node.ports().inputs(), vec!["in1"]);
        assert_eq!(node.ports().outputs(), vec!["out1"]);
    }
    #[test]
    fn analyze_ok() {
        let mut node = Detector::default();
        let mut input = LightResult::default();
        let input_light = LightData::Energy(DataEnergy {
            spectrum: create_he_ne_spectrum(1.0),
        });
        input.insert("in1".into(), Some(input_light.clone()));
        let output = node.analyze(input, &AnalyzerType::Energy);
        assert!(output.is_ok());
        let output = output.unwrap();
        assert!(output.contains_key("out1".into()));
        assert_eq!(output.len(), 1);
        let output = output.get("out1".into()).unwrap();
        assert!(output.is_some());
        let output = output.clone().unwrap();
        assert_eq!(output, input_light);
    }
    #[test]
    fn analyze_wrong() {
        let mut node = Detector::default();
        let mut input = LightResult::default();
        let input_light = LightData::Energy(DataEnergy {
            spectrum: create_he_ne_spectrum(1.0),
        });
        input.insert("wrong".into(), Some(input_light.clone()));
        let output = node.analyze(input, &AnalyzerType::Energy);
        assert!(output.is_ok());
        let output = output.unwrap();
        let output = output.get("out1".into()).unwrap();
        assert!(output.is_none());
    }
    #[test]
    fn analyze_inverse() {
        let mut node = Detector::default();
        node.set_property("inverted", true.into()).unwrap();
        let mut input = LightResult::default();
        let input_light = LightData::Energy(DataEnergy {
            spectrum: create_he_ne_spectrum(1.0),
        });
        input.insert("out1".into(), Some(input_light.clone()));

        let output = node.analyze(input, &AnalyzerType::Energy);
        assert!(output.is_ok());
        let output = output.unwrap();
        assert!(output.contains_key("in1".into()));
        assert_eq!(output.len(), 1);
        let output = output.get("in1".into()).unwrap();
        assert!(output.is_some());
        let output = output.clone().unwrap();
        assert_eq!(output, input_light);
    }