Skip to content
Snippets Groups Projects
Commit 51d96526 authored by Udo Eisenbarth's avatar Udo Eisenbarth :speech_balloon:
Browse files

Merge branch '19-implement-save-restore-of-opticscenery' into 'main'

Implement basic serialization / deserialization of OPOSSUM models

Closes #19

See merge request !16
parents fa46239a deb3a8f0
No related branches found
No related tags found
1 merge request!16Implement basic serialization / deserialization of OPOSSUM models
Pipeline #7600 canceled
...@@ -4,8 +4,8 @@ ...@@ -4,8 +4,8 @@
/book /book
*.dot *.dot
*.svg *.svg
# exclude OPOSSUM model files
*.opm
# include dot files in /files_for_testing/* # include dot files in /files_for_testing/*
!/files_for_testing/** !/files_for_testing/**
!/logo/** !/logo/**
...@@ -23,7 +23,7 @@ fn main() -> Result<(), OpossumError> { ...@@ -23,7 +23,7 @@ fn main() -> Result<(), OpossumError> {
nested_group.map_input_port(nested_g_n1, "front", "in1")?; nested_group.map_input_port(nested_g_n1, "front", "in1")?;
nested_group.map_output_port(nested_g_n2, "rear", "out1")?; nested_group.map_output_port(nested_g_n2, "rear", "out1")?;
println!("{}", serde_yaml::to_string(&group1).unwrap());
let nested_group_index = group1.add_node(nested_group); let nested_group_index = group1.add_node(nested_group);
group1.connect_nodes(nested_group_index, "out1", g1_n1, "front")?; group1.connect_nodes(nested_group_index, "out1", g1_n1, "front")?;
...@@ -38,8 +38,10 @@ fn main() -> Result<(), OpossumError> { ...@@ -38,8 +38,10 @@ fn main() -> Result<(), OpossumError> {
let scene_g1 = scenery.add_node(group1); let scene_g1 = scenery.add_node(group1);
let scene_g2 = scenery.add_node(group2); let scene_g2 = scenery.add_node(group2);
// set_output_port // set_output_port
scenery.connect_nodes(scene_g1, "out1", scene_g2, "in1")?; scenery.connect_nodes(scene_g1, "out1", scene_g2, "in1")?;
println!("{}", serde_yaml::to_string(&scenery).unwrap());
let path = "graph_group.dot"; let path = "graph_group.dot";
let mut output = File::create(path).unwrap(); let mut output = File::create(path).unwrap();
write!(output, "{}", scenery.to_dot("LR")?).unwrap(); write!(output, "{}", scenery.to_dot("LR")?).unwrap();
......
...@@ -12,7 +12,17 @@ fn main() -> Result<(), OpossumError> { ...@@ -12,7 +12,17 @@ fn main() -> Result<(), OpossumError> {
let node1 = scenery.add_node(Dummy::new("dummy1")); let node1 = scenery.add_node(Dummy::new("dummy1"));
let node2 = scenery.add_node(Dummy::new("dummy2")); let node2 = scenery.add_node(Dummy::new("dummy2"));
scenery.connect_nodes(node1, "rear", node2, "front")?; scenery.connect_nodes(node1, "rear", node2, "front")?;
println!("{}", serde_yaml::to_string(&scenery).unwrap());
let serialized=serde_yaml::to_string(&scenery).unwrap();
println!("{}", serialized);
let path = "opticscenery.opm";
let mut output = File::create(path).unwrap();
write!(output, "{}", serialized).unwrap();
let restored= serde_yaml::from_str::<OpticScenery>(&serialized);
println!("{:?}", restored);
let path = "graph.dot"; let path = "graph.dot";
let mut output = File::create(path).unwrap(); let mut output = File::create(path).unwrap();
write!(output, "{}", scenery.to_dot("")?).unwrap(); write!(output, "{}", scenery.to_dot("")?).unwrap();
......
use opossum::{optical::OpticGraph, error::OpossumError};
fn main() -> Result<(), OpossumError>{
let optic_graph=OpticGraph::default();
let serialized= serde_yaml::to_string(&optic_graph).unwrap();
println!("serialized:\n{}", serialized);
let restored_ref = serde_yaml::from_str::<OpticGraph>(&serialized).unwrap();
println!("restored:\n{:?}", restored_ref);
Ok(())
}
\ No newline at end of file
use std::{cell::RefCell, rc::Rc};
use opossum::{optical::OpticRef, nodes::Dummy, error::OpossumError};
fn main() -> Result<(), OpossumError>{
let optic_ref=OpticRef(Rc::new(RefCell::new(Dummy::default())));
let serialized= serde_yaml::to_string(&optic_ref).unwrap();
println!("serialized:\n{}", serialized);
let restored_ref = serde_yaml::from_str::<OpticRef>(&serialized).unwrap();
println!("restored:\n{:?}", restored_ref);
Ok(())
}
\ No newline at end of file
//! Data structures containing the light information flowing between [`Opticals`](crate::optical::Optical). //! Data structures containing the light information flowing between [`Opticals`](crate::optical::Optical).
use serde_derive::Serialize; use serde_derive::{Serialize, Deserialize};
use std::fmt::Display; use std::fmt::Display;
use uom::fmt::DisplayStyle::Abbreviation; use uom::fmt::DisplayStyle::Abbreviation;
use uom::si::{energy::joule, f64::Energy}; use uom::si::{energy::joule, f64::Energy};
...@@ -10,7 +10,7 @@ use crate::spectrum::Spectrum; ...@@ -10,7 +10,7 @@ use crate::spectrum::Spectrum;
/// [`AnalyzerType`](crate::analyzer::AnalyzerType). For example, an energy analysis ([`LightData::Energy`]) only /// [`AnalyzerType`](crate::analyzer::AnalyzerType). For example, an energy analysis ([`LightData::Energy`]) only
/// contains a [`Spectrum`] information, while a geometric analysis ([`LightData::Geometric]) constains a set of optical /// contains a [`Spectrum`] information, while a geometric analysis ([`LightData::Geometric]) constains a set of optical
/// ray data. /// ray data.
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum LightData { pub enum LightData {
/// data type used for energy analysis. /// data type used for energy analysis.
Energy(DataEnergy), Energy(DataEnergy),
...@@ -44,12 +44,12 @@ impl Display for LightData { ...@@ -44,12 +44,12 @@ impl Display for LightData {
} }
} }
} }
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DataEnergy { pub struct DataEnergy {
pub spectrum: Spectrum, pub spectrum: Spectrum,
} }
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DataGeometric { pub struct DataGeometric {
_ray: i32, _ray: i32,
} }
...@@ -48,6 +48,12 @@ fn create_default_props() -> Properties { ...@@ -48,6 +48,12 @@ fn create_default_props() -> Properties {
); );
props props
} }
impl Default for IdealFilter {
fn default() -> Self {
Self { filter_type: FilterType::Constant(1.0), props: create_default_props() }
}
}
impl IdealFilter { impl IdealFilter {
/// Creates a new [`IdealFilter`] with a given [`FilterType`]. /// Creates a new [`IdealFilter`] with a given [`FilterType`].
/// ///
......
...@@ -10,6 +10,9 @@ mod reference; ...@@ -10,6 +10,9 @@ mod reference;
mod source; mod source;
mod spectrometer; mod spectrometer;
use std::cell::RefCell;
use std::rc::Rc;
pub use beam_splitter::BeamSplitter; pub use beam_splitter::BeamSplitter;
pub use detector::Detector; pub use detector::Detector;
pub use dummy::Dummy; pub use dummy::Dummy;
...@@ -24,3 +27,22 @@ pub use energy_meter::Metertype; ...@@ -24,3 +27,22 @@ pub use energy_meter::Metertype;
pub use spectrometer::Spectrometer; pub use spectrometer::Spectrometer;
pub use spectrometer::SpectrometerType; pub use spectrometer::SpectrometerType;
use crate::error::OpossumError;
use crate::optical::OpticRef;
pub fn create_node_ref(node_type: &str) -> Result<OpticRef,OpossumError> {
match node_type {
"dummy" => Ok(OpticRef(Rc::new(RefCell::new(Dummy::default())))),
"detector" => Ok(OpticRef(Rc::new(RefCell::new(Detector::default())))),
"beam splitter" => Ok(OpticRef(Rc::new(RefCell::new(BeamSplitter::default())))),
"energy meter" => Ok(OpticRef(Rc::new(RefCell::new(EnergyMeter::default())))),
"group" => Ok(OpticRef(Rc::new(RefCell::new(NodeGroup::default())))),
"ideal filter" => Ok(OpticRef(Rc::new(RefCell::new(IdealFilter::default())))),
"reference" => Ok(OpticRef(Rc::new(RefCell::new(NodeReference::default())))),
"real lens" => Ok(OpticRef(Rc::new(RefCell::new(RealLens::default())))),
"light source" => Ok(OpticRef(Rc::new(RefCell::new(Source::default())))),
"spectrometer" => Ok(OpticRef(Rc::new(RefCell::new(Spectrometer::default())))),
_ => Err(OpossumError::Other(format!("cannot create node type {}", node_type)))
}
}
\ No newline at end of file
...@@ -10,7 +10,7 @@ use crate::properties::Properties; ...@@ -10,7 +10,7 @@ use crate::properties::Properties;
type Result<T> = std::result::Result<T, OpossumError>; type Result<T> = std::result::Result<T, OpossumError>;
#[derive(Debug)] #[derive(Debug, Default)]
/// A virtual component referring to another existing component. /// A virtual component referring to another existing component.
/// ///
/// This node type is necessary in order to model resonators (loops) or double-pass systems. /// This node type is necessary in order to model resonators (loops) or double-pass systems.
...@@ -21,14 +21,15 @@ type Result<T> = std::result::Result<T, OpossumError>; ...@@ -21,14 +21,15 @@ type Result<T> = std::result::Result<T, OpossumError>;
/// - Outputs /// - Outputs
/// - output ports of the referenced [`Optical`] /// - output ports of the referenced [`Optical`]
pub struct NodeReference { pub struct NodeReference {
reference: Weak<RefCell<dyn Optical>>, reference: Option<Weak<RefCell<dyn Optical>>>,
props: Properties props: Properties
} }
impl NodeReference { impl NodeReference {
// Create new [`OpticNode`] (of type [`NodeReference`]) from another existing [`OpticNode`]. // Create new [`OpticNode`] (of type [`NodeReference`]) from another existing [`OpticNode`].
pub fn from_node(node: Rc<RefCell<dyn Optical>>) -> Self { pub fn from_node(node: Rc<RefCell<dyn Optical>>) -> Self {
Self { Self {
reference: Rc::downgrade(&node), reference: Some(Rc::downgrade(&node)),
props: Properties::default() props: Properties::default()
} }
} }
...@@ -40,7 +41,12 @@ impl Optical for NodeReference { ...@@ -40,7 +41,12 @@ impl Optical for NodeReference {
} }
fn ports(&self) -> OpticPorts { fn ports(&self) -> OpticPorts {
self.reference.upgrade().unwrap().borrow().ports().clone() if let Some(rf)= &self.reference {
rf.upgrade().unwrap().borrow().ports().clone()
} else {
OpticPorts::default()
}
} }
fn analyze( fn analyze(
...@@ -48,11 +54,16 @@ impl Optical for NodeReference { ...@@ -48,11 +54,16 @@ impl Optical for NodeReference {
incoming_data: LightResult, incoming_data: LightResult,
analyzer_type: &AnalyzerType, analyzer_type: &AnalyzerType,
) -> Result<LightResult> { ) -> Result<LightResult> {
self.reference if let Some(rf)= &self.reference {
rf
.upgrade() .upgrade()
.unwrap() .unwrap()
.borrow_mut() .borrow_mut()
.analyze(incoming_data, analyzer_type) .analyze(incoming_data, analyzer_type)
} else {
Err(OpossumError::Analysis("reference node has no reference defined".into()))
}
} }
fn properties(&self) -> &Properties { fn properties(&self) -> &Properties {
&self.props &self.props
......
...@@ -7,14 +7,15 @@ use crate::error::OpossumError; ...@@ -7,14 +7,15 @@ use crate::error::OpossumError;
use crate::light::Light; use crate::light::Light;
use crate::lightdata::LightData; use crate::lightdata::LightData;
use crate::nodes::NodeGroup; use crate::nodes::NodeGroup;
use crate::optical::{LightResult, OpticRef, Optical, OpticGraph}; use crate::optical::{LightResult, OpticGraph, OpticRef, Optical};
use crate::properties::{Properties, Property, Proptype}; use crate::properties::{Properties, Property, Proptype};
use petgraph::algo::*; use petgraph::algo::*;
use petgraph::prelude::{DiGraph, NodeIndex}; use petgraph::prelude::NodeIndex;
use petgraph::visit::EdgeRef; use petgraph::visit::EdgeRef;
use petgraph::Direction::Incoming; use petgraph::Direction::Incoming;
use serde::ser::SerializeStruct; //use serde::ser::SerializeStruct;
use serde::Serialize; //use serde::Serialize;
use serde_derive::{Serialize, Deserialize};
type Result<T> = std::result::Result<T, OpossumError>; type Result<T> = std::result::Result<T, OpossumError>;
...@@ -39,10 +40,11 @@ type Result<T> = std::result::Result<T, OpossumError>; ...@@ -39,10 +40,11 @@ type Result<T> = std::result::Result<T, OpossumError>;
/// } /// }
/// ///
/// ``` /// ```
#[derive(Debug, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct OpticScenery { pub struct OpticScenery {
g: DiGraph<OpticRef, Light>, #[serde(rename = "graph")]
description: String, g: OpticGraph,
#[serde(rename = "properties")]
props: Properties, props: Properties,
} }
...@@ -59,20 +61,23 @@ fn create_default_props() -> Properties { ...@@ -59,20 +61,23 @@ fn create_default_props() -> Properties {
impl Default for OpticScenery { impl Default for OpticScenery {
fn default() -> Self { fn default() -> Self {
Self { g: Default::default(), description: Default::default(), props: create_default_props() } Self {
g: Default::default(),
props: create_default_props(),
}
} }
} }
impl OpticScenery { impl OpticScenery {
/// Creates a new (empty) [`OpticScenery`]. /// Creates a new (empty) [`OpticScenery`].
pub fn new() -> Self { pub fn new() -> Self {
Self::default() Self::default()
} }
/// Add a given [`Optical`] (Source, Detector, Lens, etc.) to the graph of this [`OpticScenery`]. /// Add a given [`Optical`] (Source, Detector, Lens, etc.) to the graph of this [`OpticScenery`].
/// ///
/// This command just adds an [`Optical`] to the graph. It does not connect /// This command just adds an [`Optical`] to the graph. It does not connect
/// it to existing nodes in the graph. The given optical element is consumed (owned) by the [`OpticScenery`]. /// it to existing nodes in the graph. The given optical element is consumed (owned) by the [`OpticScenery`].
pub fn add_node<T: Optical + 'static>(&mut self, node: T) -> NodeIndex { pub fn add_node<T: Optical + 'static>(&mut self, node: T) -> NodeIndex {
self.g.add_node(OpticRef(Rc::new(RefCell::new(node)))) self.g.0.add_node(OpticRef(Rc::new(RefCell::new(node))))
} }
/// Connect (already existing) nodes denoted by the respective `NodeIndex`. /// Connect (already existing) nodes denoted by the respective `NodeIndex`.
/// ///
...@@ -85,7 +90,7 @@ impl OpticScenery { ...@@ -85,7 +90,7 @@ impl OpticScenery {
target_node: NodeIndex, target_node: NodeIndex,
target_port: &str, target_port: &str,
) -> Result<()> { ) -> Result<()> {
if let Some(source) = self.g.node_weight(src_node) { if let Some(source) = self.g.0.node_weight(src_node) {
if !source if !source
.0 .0
.borrow() .borrow()
...@@ -104,7 +109,7 @@ impl OpticScenery { ...@@ -104,7 +109,7 @@ impl OpticScenery {
"source node with given index does not exist".into(), "source node with given index does not exist".into(),
)); ));
} }
if let Some(target) = self.g.node_weight(target_node) { if let Some(target) = self.g.0.node_weight(target_node) {
if !target if !target
.0 .0
.borrow() .borrow()
...@@ -135,11 +140,12 @@ impl OpticScenery { ...@@ -135,11 +140,12 @@ impl OpticScenery {
target_port target_port
))); )));
} }
let edge_index = self let edge_index =
.g self.g
.add_edge(src_node, target_node, Light::new(src_port, target_port)); .0
if is_cyclic_directed(&self.g) { .add_edge(src_node, target_node, Light::new(src_port, target_port));
self.g.remove_edge(edge_index); if is_cyclic_directed(&self.g.0) {
self.g.0.remove_edge(edge_index);
return Err(OpossumError::OpticScenery( return Err(OpossumError::OpticScenery(
"connecting the given nodes would form a loop".into(), "connecting the given nodes would form a loop".into(),
)); ));
...@@ -148,11 +154,13 @@ impl OpticScenery { ...@@ -148,11 +154,13 @@ impl OpticScenery {
} }
fn src_node_port_exists(&self, src_node: NodeIndex, src_port: &str) -> bool { fn src_node_port_exists(&self, src_node: NodeIndex, src_port: &str) -> bool {
self.g self.g
.0
.edges_directed(src_node, petgraph::Direction::Outgoing) .edges_directed(src_node, petgraph::Direction::Outgoing)
.any(|e| e.weight().src_port() == src_port) .any(|e| e.weight().src_port() == src_port)
} }
fn target_node_port_exists(&self, target_node: NodeIndex, target_port: &str) -> bool { fn target_node_port_exists(&self, target_node: NodeIndex, target_port: &str) -> bool {
self.g self.g
.0
.edges_directed(target_node, petgraph::Direction::Incoming) .edges_directed(target_node, petgraph::Direction::Incoming)
.any(|e| e.weight().target_port() == target_port) .any(|e| e.weight().target_port() == target_port)
} }
...@@ -164,7 +172,7 @@ impl OpticScenery { ...@@ -164,7 +172,7 @@ impl OpticScenery {
/// ///
/// This function will return [`OpossumError::OpticScenery`] if the node does not exist. /// This function will return [`OpossumError::OpticScenery`] if the node does not exist.
pub fn node(&self, node: NodeIndex) -> Result<Rc<RefCell<dyn Optical>>> { pub fn node(&self, node: NodeIndex) -> Result<Rc<RefCell<dyn Optical>>> {
if let Some(node) = self.g.node_weight(node) { if let Some(node) = self.g.0.node_weight(node) {
Ok(node.0.clone()) Ok(node.0.clone())
} else { } else {
Err(OpossumError::OpticScenery( Err(OpossumError::OpticScenery(
...@@ -175,22 +183,27 @@ impl OpticScenery { ...@@ -175,22 +183,27 @@ impl OpticScenery {
/// Export the optic graph, including ports, into the `dot` format to be used in combination with the [`graphviz`](https://graphviz.org/) software. /// Export the optic graph, including ports, into the `dot` format to be used in combination with the [`graphviz`](https://graphviz.org/) software.
pub fn to_dot(&self, rankdir: &str) -> Result<String> { pub fn to_dot(&self, rankdir: &str) -> Result<String> {
//check direction //check direction
let rankdir = if rankdir != "LR" {"TB"}else{"LR"}; let rankdir = if rankdir != "LR" { "TB" } else { "LR" };
let mut dot_string = self.add_dot_header(rankdir); let mut dot_string = self.add_dot_header(rankdir);
for node_idx in self.g.node_indices() { for node_idx in self.g.0.node_indices() {
let node = self.g.node_weight(node_idx).unwrap(); let node = self.g.0.node_weight(node_idx).unwrap();
let node_name=node.0.borrow().name().to_owned(); let node_name = node.0.borrow().name().to_owned();
let inverted= node.0.borrow().inverted(); let inverted = node.0.borrow().inverted();
let ports=node.0.borrow().ports(); let ports = node.0.borrow().ports();
dot_string += &node.0 dot_string += &node.0.borrow().to_dot(
.borrow() &format!("{}", node_idx.index()),
.to_dot(&format!("{}", node_idx.index()), &node_name, inverted, &ports, "".to_owned(), rankdir)?; &node_name,
inverted,
&ports,
"".to_owned(),
rankdir,
)?;
} }
for edge in self.g.edge_indices() { for edge in self.g.0.edge_indices() {
let light: &Light = self.g.edge_weight(edge).unwrap(); let light: &Light = self.g.0.edge_weight(edge).unwrap();
let end_nodes = self.g.edge_endpoints(edge).unwrap(); let end_nodes = self.g.0.edge_endpoints(edge).unwrap();
let src_edge_str = let src_edge_str =
self.create_node_edge_str(end_nodes.0, light.src_port(), "".to_owned())?; self.create_node_edge_str(end_nodes.0, light.src_port(), "".to_owned())?;
...@@ -201,14 +214,13 @@ impl OpticScenery { ...@@ -201,14 +214,13 @@ impl OpticScenery {
} }
dot_string.push_str("}\n"); dot_string.push_str("}\n");
Ok(dot_string) Ok(dot_string)
} }
/// Returns the dot-file header of this [`OpticScenery`] graph. /// Returns the dot-file header of this [`OpticScenery`] graph.
fn add_dot_header(&self, rankdir: &str) -> String { fn add_dot_header(&self, rankdir: &str) -> String {
let mut dot_string = "digraph {\n\tfontsize = 8\n".to_owned(); let mut dot_string = "digraph {\n\tfontsize = 8\n".to_owned();
dot_string.push_str("\tcompound = true;\n"); dot_string.push_str("\tcompound = true;\n");
dot_string.push_str(&format!("\trankdir = \"{}\";\n", rankdir)); dot_string.push_str(&format!("\trankdir = \"{}\";\n", rankdir));
dot_string.push_str(&format!("\tlabel=\"{}\"\n", self.description)); dot_string.push_str(&format!("\tlabel=\"{}\"\n", self.description()));
dot_string.push_str("\tfontname=\"Helvetica,Arial,sans-serif\"\n"); dot_string.push_str("\tfontname=\"Helvetica,Arial,sans-serif\"\n");
dot_string.push_str("\tnode [fontname=\"Helvetica,Arial,sans-serif\" fontsize = 10]\n"); dot_string.push_str("\tnode [fontname=\"Helvetica,Arial,sans-serif\" fontsize = 10]\n");
dot_string.push_str("\tedge [fontname=\"Helvetica,Arial,sans-serif\"]\n\n"); dot_string.push_str("\tedge [fontname=\"Helvetica,Arial,sans-serif\"]\n\n");
...@@ -220,7 +232,7 @@ impl OpticScenery { ...@@ -220,7 +232,7 @@ impl OpticScenery {
light_port: &str, light_port: &str,
mut parent_identifier: String, mut parent_identifier: String,
) -> Result<String> { ) -> Result<String> {
let node = self.g.node_weight(end_node).unwrap().0.borrow(); let node = self.g.0.node_weight(end_node).unwrap().0.borrow();
parent_identifier = if parent_identifier.is_empty() { parent_identifier = if parent_identifier.is_empty() {
format!("i{}", end_node.index()) format!("i{}", end_node.index())
} else { } else {
...@@ -236,10 +248,10 @@ impl OpticScenery { ...@@ -236,10 +248,10 @@ impl OpticScenery {
} }
/// Analyze this [`OpticScenery`] based on a given [`AnalyzerType`]. /// Analyze this [`OpticScenery`] based on a given [`AnalyzerType`].
pub fn analyze(&mut self, analyzer_type: &AnalyzerType) -> Result<()> { pub fn analyze(&mut self, analyzer_type: &AnalyzerType) -> Result<()> {
let sorted = toposort(&self.g, None); let sorted = toposort(&self.g.0, None);
if let Ok(sorted) = sorted { if let Ok(sorted) = sorted {
for idx in sorted { for idx in sorted {
let node = self.g.node_weight(idx).unwrap(); let node = self.g.0.node_weight(idx).unwrap();
let incoming_edges: HashMap<String, Option<LightData>> = self.incoming_edges(idx); let incoming_edges: HashMap<String, Option<LightData>> = self.incoming_edges(idx);
let outgoing_edges = node.0.borrow_mut().analyze(incoming_edges, analyzer_type)?; let outgoing_edges = node.0.borrow_mut().analyze(incoming_edges, analyzer_type)?;
for outgoing_edge in outgoing_edges { for outgoing_edge in outgoing_edges {
...@@ -255,18 +267,30 @@ impl OpticScenery { ...@@ -255,18 +267,30 @@ impl OpticScenery {
} }
/// Sets the description of this [`OpticScenery`]. /// Sets the description of this [`OpticScenery`].
pub fn set_description(&mut self, description: &str) { pub fn set_description(&mut self, description: &str) {
self.description = description.into(); self.props
.set(
"description",
Property {
prop: Proptype::String(description.into()),
},
)
.unwrap();
} }
/// Returns a reference to the description of this [`OpticScenery`]. /// Returns a reference to the description of this [`OpticScenery`].
pub fn description(&self) -> &str { pub fn description(&self) -> &str {
self.description.as_ref() let prop = self.props.get("description").unwrap();
if let Proptype::String(dsc) = &prop.prop {
dsc
} else {
""
}
} }
/// Returns the nodes unordered of this [`OpticScenery`]. /// Returns the nodes unordered of this [`OpticScenery`].
pub fn nodes_unordered(&self) -> Vec<NodeIndex> { pub fn nodes_unordered(&self) -> Vec<NodeIndex> {
self.g.node_indices().collect::<Vec<NodeIndex>>() self.g.0.node_indices().collect::<Vec<NodeIndex>>()
} }
fn incoming_edges(&self, idx: NodeIndex) -> LightResult { fn incoming_edges(&self, idx: NodeIndex) -> LightResult {
let edges = self.g.edges_directed(idx, petgraph::Direction::Incoming); let edges = self.g.0.edges_directed(idx, petgraph::Direction::Incoming);
edges edges
.into_iter() .into_iter()
.map(|e| { .map(|e| {
...@@ -278,28 +302,29 @@ impl OpticScenery { ...@@ -278,28 +302,29 @@ impl OpticScenery {
.collect::<HashMap<String, Option<LightData>>>() .collect::<HashMap<String, Option<LightData>>>()
} }
fn set_outgoing_edge_data(&mut self, idx: NodeIndex, port: String, data: Option<LightData>) { fn set_outgoing_edge_data(&mut self, idx: NodeIndex, port: String, data: Option<LightData>) {
let edges = self.g.edges_directed(idx, petgraph::Direction::Outgoing); let edges = self.g.0.edges_directed(idx, petgraph::Direction::Outgoing);
let edge_ref = edges let edge_ref = edges
.into_iter() .into_iter()
.filter(|idx| idx.weight().src_port() == port) .filter(|idx| idx.weight().src_port() == port)
.last(); .last();
if let Some(edge_ref) = edge_ref { if let Some(edge_ref) = edge_ref {
let edge_idx = edge_ref.id(); let edge_idx = edge_ref.id();
let light = self.g.edge_weight_mut(edge_idx); let light = self.g.0.edge_weight_mut(edge_idx);
if let Some(light) = light { if let Some(light) = light {
light.set_data(data); light.set_data(data);
} }
} // else outgoing edge not connected } // else outgoing edge not connected
} }
pub fn report(&self) { pub fn report(&self) {
let src_nodes = &self.g.externals(Incoming); let src_nodes = &self.g.0.externals(Incoming);
let detector_nodes = self let detector_nodes = self
.g .g
.0
.node_weights() .node_weights()
.filter(|node| node.0.borrow().is_detector()); .filter(|node| node.0.borrow().is_detector());
println!("Sources:"); println!("Sources:");
for idx in src_nodes.clone() { for idx in src_nodes.clone() {
let node = self.g.node_weight(idx).unwrap(); let node = self.g.0.node_weight(idx).unwrap();
println!("{:?}", node.0.borrow()); println!("{:?}", node.0.borrow());
let file_name = node.0.borrow().name().to_owned() + ".svg"; let file_name = node.0.borrow().name().to_owned() + ".svg";
node.0.borrow().export_data(&file_name); node.0.borrow().export_data(&file_name);
...@@ -311,41 +336,40 @@ impl OpticScenery { ...@@ -311,41 +336,40 @@ impl OpticScenery {
node.0.borrow().export_data(&file_name); node.0.borrow().export_data(&file_name);
} }
} }
} }
impl Serialize for OpticScenery { // impl Serialize for OpticScenery {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> // fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where // where
S: serde::Serializer, // S: serde::Serializer,
{ // {
let mut scenery = serializer.serialize_struct("optic scenery", 2)?; // let mut scenery = serializer.serialize_struct("optic scenery", 2)?;
scenery.serialize_field("graph", &OpticGraph(self.g.clone()))?; // scenery.serialize_field("graph", &OpticGraph(self.g.0.clone()))?;
scenery.serialize_field("properties", &self.props)?; // scenery.serialize_field("properties", &self.props)?;
scenery.end() // scenery.end()
} // }
} // }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::nodes::Metertype; use crate::nodes::Metertype;
use crate::properties::{Property, Proptype}; use crate::properties::{Property, Proptype};
use super::super::nodes::{Dummy, BeamSplitter, EnergyMeter, Source}; use super::super::nodes::{BeamSplitter, Dummy, EnergyMeter, Source};
use std::{fs::File,io::Read};
use std::io::Write;
use super::*; use super::*;
use std::io::Write;
use std::{fs::File, io::Read};
#[test] #[test]
fn new() { fn new() {
let scenery = OpticScenery::new(); let scenery = OpticScenery::new();
assert_eq!(scenery.description, "".to_owned()); assert_eq!(scenery.description(), "".to_owned());
assert_eq!(scenery.g.edge_count(), 0); assert_eq!(scenery.g.0.edge_count(), 0);
assert_eq!(scenery.g.node_count(), 0); assert_eq!(scenery.g.0.node_count(), 0);
} }
#[test] #[test]
fn add_node() { fn add_node() {
let mut scenery = OpticScenery::new(); let mut scenery = OpticScenery::new();
scenery.add_node(Dummy::new("n1")); scenery.add_node(Dummy::new("n1"));
assert_eq!(scenery.g.node_count(), 1); assert_eq!(scenery.g.0.node_count(), 1);
} }
#[test] #[test]
fn connect_nodes_ok() { fn connect_nodes_ok() {
...@@ -353,7 +377,7 @@ mod test { ...@@ -353,7 +377,7 @@ mod test {
let n1 = scenery.add_node(Dummy::new("Test")); let n1 = scenery.add_node(Dummy::new("Test"));
let n2 = scenery.add_node(Dummy::new("Test")); let n2 = scenery.add_node(Dummy::new("Test"));
assert!(scenery.connect_nodes(n1, "rear", n2, "front").is_ok()); assert!(scenery.connect_nodes(n1, "rear", n2, "front").is_ok());
assert_eq!(scenery.g.edge_count(), 1); assert_eq!(scenery.g.0.edge_count(), 1);
} }
#[test] #[test]
fn connect_nodes_failure() { fn connect_nodes_failure() {
...@@ -374,7 +398,7 @@ mod test { ...@@ -374,7 +398,7 @@ mod test {
let n2 = scenery.add_node(Dummy::new("Test")); let n2 = scenery.add_node(Dummy::new("Test"));
assert!(scenery.connect_nodes(n1, "rear", n2, "front").is_ok()); assert!(scenery.connect_nodes(n1, "rear", n2, "front").is_ok());
assert!(scenery.connect_nodes(n2, "rear", n1, "front").is_err()); assert!(scenery.connect_nodes(n2, "rear", n1, "front").is_err());
assert_eq!(scenery.g.edge_count(), 1); assert_eq!(scenery.g.0.edge_count(), 1);
} }
#[test] #[test]
fn to_dot_empty() { fn to_dot_empty() {
...@@ -387,7 +411,7 @@ mod test { ...@@ -387,7 +411,7 @@ mod test {
let _ = File::open(path).unwrap().read_to_string(file_content_lr); let _ = File::open(path).unwrap().read_to_string(file_content_lr);
let mut scenery = OpticScenery::new(); let mut scenery = OpticScenery::new();
scenery.set_description("Test".into()); scenery.set_description("Test".into());
let scenery_dot_str_tb = scenery.to_dot("TB").unwrap(); let scenery_dot_str_tb = scenery.to_dot("TB").unwrap();
let scenery_dot_str_lr = scenery.to_dot("LR").unwrap(); let scenery_dot_str_lr = scenery.to_dot("LR").unwrap();
...@@ -425,19 +449,35 @@ mod test { ...@@ -425,19 +449,35 @@ mod test {
let file_content_lr = &mut "".to_owned(); let file_content_lr = &mut "".to_owned();
let _ = File::open(path).unwrap().read_to_string(file_content_lr); let _ = File::open(path).unwrap().read_to_string(file_content_lr);
let mut scenery = OpticScenery::new(); let mut scenery = OpticScenery::new();
scenery.set_description("SceneryTest".into()); scenery.set_description("SceneryTest".into());
let i_s = scenery.add_node(Source::new("Source", LightData::Fourier)); let i_s = scenery.add_node(Source::new("Source", LightData::Fourier));
let mut bs=BeamSplitter::new(0.6).unwrap(); let mut bs = BeamSplitter::new(0.6).unwrap();
bs.set_property("name", Property {prop: Proptype::String("Beam splitter".into())}).unwrap(); bs.set_property(
"name",
Property {
prop: Proptype::String("Beam splitter".into()),
},
)
.unwrap();
let i_bs = scenery.add_node(bs); let i_bs = scenery.add_node(bs);
let i_d1 = scenery.add_node(EnergyMeter::new("Energy meter 1",Metertype::IdealEnergyMeter)); let i_d1 = scenery.add_node(EnergyMeter::new(
let i_d2 = scenery.add_node(EnergyMeter::new("Energy meter 2",Metertype::IdealEnergyMeter)); "Energy meter 1",
Metertype::IdealEnergyMeter,
scenery.connect_nodes(i_s, "out1", i_bs, "input1").unwrap(); ));
scenery.connect_nodes(i_bs, "out1_trans1_refl2", i_d1, "in1").unwrap(); let i_d2 = scenery.add_node(EnergyMeter::new(
scenery.connect_nodes(i_bs, "out2_trans2_refl1", i_d2, "in1").unwrap(); "Energy meter 2",
Metertype::IdealEnergyMeter,
));
scenery.connect_nodes(i_s, "out1", i_bs, "input1").unwrap();
scenery
.connect_nodes(i_bs, "out1_trans1_refl2", i_d1, "in1")
.unwrap();
scenery
.connect_nodes(i_bs, "out2_trans2_refl1", i_d2, "in1")
.unwrap();
let scenery_dot_str_tb = scenery.to_dot("TB").unwrap(); let scenery_dot_str_tb = scenery.to_dot("TB").unwrap();
let scenery_dot_str_lr = scenery.to_dot("LR").unwrap(); let scenery_dot_str_lr = scenery.to_dot("LR").unwrap();
...@@ -452,7 +492,7 @@ mod test { ...@@ -452,7 +492,7 @@ mod test {
fn set_description() { fn set_description() {
let mut scenery = OpticScenery::new(); let mut scenery = OpticScenery::new();
scenery.set_description("Test".into()); scenery.set_description("Test".into());
assert_eq!(scenery.description, "Test") assert_eq!(scenery.description(), "Test")
} }
#[test] #[test]
fn description() { fn description() {
......
use petgraph::prelude::DiGraph;
use petgraph::stable_graph::NodeIndex;
use serde::ser::SerializeStruct;
use serde::Serialize;
use crate::analyzer::AnalyzerType; use crate::analyzer::AnalyzerType;
use crate::dottable::Dottable; use crate::dottable::Dottable;
use crate::error::OpossumError; use crate::error::OpossumError;
use crate::light::Light; use crate::light::Light;
use crate::lightdata::LightData; use crate::lightdata::LightData;
use crate::nodes::NodeGroup; use crate::nodes::{create_node_ref, NodeGroup};
use crate::optic_ports::OpticPorts; use crate::optic_ports::OpticPorts;
use crate::properties::{Properties, Property}; use crate::properties::{Properties, Property};
use core::fmt::Debug; use core::fmt::Debug;
use petgraph::prelude::DiGraph;
use petgraph::stable_graph::NodeIndex;
use serde::de::{self, Deserialize, MapAccess, SeqAccess, Visitor};
use serde::ser::SerializeStruct;
use serde::Serialize;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
...@@ -74,6 +74,16 @@ pub trait Optical: Dottable { ...@@ -74,6 +74,16 @@ pub trait Optical: Dottable {
fn set_property(&mut self, _name: &str, _prop: Property) -> Result<()> { fn set_property(&mut self, _name: &str, _prop: Property) -> Result<()> {
Ok(()) Ok(())
} }
fn set_properties(&mut self, properties: &Properties) -> Result<()> {
let own_properties = self.properties().props.clone();
for prop in properties.props.iter() {
if own_properties.contains_key(prop.0) {
self.set_property(prop.0, prop.1.clone())?;
}
}
Ok(())
}
} }
impl Debug for dyn Optical { impl Debug for dyn Optical {
...@@ -108,15 +118,106 @@ impl Serialize for OpticGraph { ...@@ -108,15 +118,106 @@ impl Serialize for OpticGraph {
) )
}) })
.collect::<Vec<(NodeIndex, NodeIndex, &str, &str)>>(); .collect::<Vec<(NodeIndex, NodeIndex, &str, &str)>>();
// let edges = g
// .edge_weights()
// .map(|n| (n.src_port(), n.target_port()).to_owned())
// .collect::<Vec<(&str, &str)>>();
graph.serialize_field("edges", &edgeidx)?; graph.serialize_field("edges", &edgeidx)?;
graph.end() graph.end()
} }
} }
impl<'de> Deserialize<'de> for OpticGraph {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
enum Field {
Nodes,
Edges,
}
const FIELDS: &[&str] = &["nodes", "edges"];
impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct FieldVisitor;
impl<'de> Visitor<'de> for FieldVisitor {
type Value = Field;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("`nodes` or `edges`")
}
fn visit_str<E>(self, value: &str) -> std::result::Result<Field, E>
where
E: de::Error,
{
match value {
"nodes" => Ok(Field::Nodes),
"edges" => Ok(Field::Edges),
_ => Err(de::Error::unknown_field(value, FIELDS)),
}
}
}
deserializer.deserialize_identifier(FieldVisitor)
}
}
struct OpticGraphVisitor;
impl<'de> Visitor<'de> for OpticGraphVisitor {
type Value = OpticGraph;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("an OpticGraph")
}
// fn visit_seq<A>(self, mut seq: A) -> std::result::Result<OpticGraph, A::Error>
// where
// A: SeqAccess<'de>,
// {
// println!("visit seq");
// let g = OpticGraph::default();
// Ok(g)
// }
fn visit_map<A>(self, mut map: A) -> std::result::Result<OpticGraph, A::Error>
where
A: MapAccess<'de>,
{
let mut g = OpticGraph::default();
let mut nodes: Option<Vec<OpticRef>> = None;
let mut edges: Option<Vec<(NodeIndex, NodeIndex, &str, &str)>> = None;
while let Some(key) = map.next_key()? {
match key {
Field::Nodes => {
if nodes.is_some() {
return Err(de::Error::duplicate_field("nodes"));
}
nodes = Some(map.next_value::<Vec<OpticRef>>()?);
}
Field::Edges => {
if edges.is_some() {
return Err(de::Error::duplicate_field("edges"));
}
edges =
Some(map.next_value::<Vec<(NodeIndex, NodeIndex, &str, &str)>>()?);
}
}
}
let nodes = nodes.ok_or_else(|| de::Error::missing_field("nodes"))?;
let edges = edges.ok_or_else(|| de::Error::missing_field("edges"))?;
for node in nodes.iter() {
g.0.add_node(node.clone());
}
for edge in edges.iter() {
g.0
.add_edge(edge.0, edge.1, Light::new(edge.2, edge.3));
}
Ok(g)
}
}
deserializer.deserialize_struct("OpticGraph", FIELDS, OpticGraphVisitor)
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct OpticRef(pub Rc<RefCell<dyn Optical>>); pub struct OpticRef(pub Rc<RefCell<dyn Optical>>);
...@@ -132,25 +233,107 @@ impl Serialize for OpticRef { ...@@ -132,25 +233,107 @@ impl Serialize for OpticRef {
} }
} }
#[cfg(test)] impl<'de> Deserialize<'de> for OpticRef {
mod test { fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
// #[test] where
// #[ignore] D: serde::Deserializer<'de>,
// fn to_dot() { {
// let node = OpticNode::new("Test", Dummy::default()); enum Field {
// assert_eq!( NodeType,
// node.to_dot("i0", "".to_owned()).unwrap(), Properties,
// " i0 [label=\"Test\"]\n".to_owned() }
// ) const FIELDS: &[&str] = &["type", "properties"];
// }
// #[test] impl<'de> Deserialize<'de> for Field {
// #[ignore] fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
// fn to_dot_inverted() { where
// let mut node = OpticNode::new("Test", Dummy::default()); D: serde::Deserializer<'de>,
// node.set_inverted(true); {
// assert_eq!( struct FieldVisitor;
// node.to_dot("i0", "".to_owned()).unwrap(),
// " i0 [label=\"Test(inv)\"]\n".to_owned() impl<'de> Visitor<'de> for FieldVisitor {
// ) type Value = Field;
// }
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("`type` or `properties`")
}
fn visit_str<E>(self, value: &str) -> std::result::Result<Field, E>
where
E: de::Error,
{
match value {
"type" => Ok(Field::NodeType),
"properties" => Ok(Field::Properties),
_ => Err(de::Error::unknown_field(value, FIELDS)),
}
}
}
deserializer.deserialize_identifier(FieldVisitor)
}
}
struct OpticRefVisitor;
impl<'de> Visitor<'de> for OpticRefVisitor {
type Value = OpticRef;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a struct OpticRef")
}
fn visit_seq<A>(self, mut seq: A) -> std::result::Result<OpticRef, A::Error>
where
A: SeqAccess<'de>,
{
let node_type = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
let properties = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
let node =
create_node_ref(node_type).map_err(|e| de::Error::custom(e.to_string()))?;
node.0
.borrow_mut()
.set_properties(&properties)
.map_err(|e| de::Error::custom(e.to_string()))?;
Ok(node)
}
fn visit_map<A>(self, mut map: A) -> std::result::Result<OpticRef, A::Error>
where
A: MapAccess<'de>,
{
let mut node_type = None;
let mut properties = None;
while let Some(key) = map.next_key()? {
match key {
Field::NodeType => {
if node_type.is_some() {
return Err(de::Error::duplicate_field("type"));
}
node_type = Some(map.next_value()?);
}
Field::Properties => {
if properties.is_some() {
return Err(de::Error::duplicate_field("properties"));
}
properties = Some(map.next_value::<Properties>()?);
}
}
}
let node_type = node_type.ok_or_else(|| de::Error::missing_field("type"))?;
let properties =
properties.ok_or_else(|| de::Error::missing_field("properties"))?;
let node =
create_node_ref(node_type).map_err(|e| de::Error::custom(e.to_string()))?;
node.0
.borrow_mut()
.set_properties(&properties)
.map_err(|e| de::Error::custom(e.to_string()))?;
Ok(node)
}
}
deserializer.deserialize_struct("OpticRef", FIELDS, OpticRefVisitor)
}
} }
use std::collections::HashMap; use std::collections::HashMap;
use serde::Serialize; // use serde::Serialize;
use serde_derive::Serialize; use serde_derive::{Serialize, Deserialize};
use crate::{error::OpossumError, lightdata::LightData, optical::OpticGraph}; use crate::{error::OpossumError, lightdata::LightData, optical::OpticGraph};
#[derive(Default, Debug, Clone)] #[derive(Default, Serialize, Deserialize, Debug, Clone)]
pub struct Properties { pub struct Properties {
props: HashMap<String, Property> pub props: HashMap<String, Property>
} }
impl Properties { impl Properties {
...@@ -33,32 +33,34 @@ impl Properties { ...@@ -33,32 +33,34 @@ impl Properties {
} }
} }
} }
impl Serialize for Properties { // impl Serialize for Properties {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> // fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where // where
S: serde::Serializer { // S: serde::Serializer {
serializer.serialize_newtype_struct("hallo", &self.props) // serializer.serialize_newtype_struct("properties", &self.props)
} // }
} // }
#[derive(Debug, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(transparent)]
pub struct Property { pub struct Property {
pub prop: Proptype pub prop: Proptype
} }
impl Serialize for Property { // impl Serialize for Property {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> // fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where // where
S: serde::Serializer { // S: serde::Serializer {
serializer.serialize_newtype_struct("hallo", &self.prop) // serializer.serialize_newtype_struct("property", &self.prop)
} // }
} // }
#[non_exhaustive] #[non_exhaustive]
#[derive(Serialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Proptype { pub enum Proptype {
String(String), String(String),
I32(i32), I32(i32),
F64(f64), F64(f64),
Bool(bool), Bool(bool),
LightData(Option<LightData>), LightData(Option<LightData>),
#[serde(skip)]
OpticGraph(OpticGraph) OpticGraph(OpticGraph)
} }
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment