dune_core/solution.rs
1//! Analysis results in the shape of a rawfile plot (D-0008): named
2//! variables with [`VarType`](crate::VarType)s and real or complex
3//! columns ([`Data`](crate::Data), both re-exported from `dune_raw`),
4//! so the oracle, the CLI and the bindings all read the same thing.
5
6use dune_raw::{Data, Plot, VarType, Variable};
7use num_complex::Complex64;
8
9/// One analysis plot: what a rawfile plot holds, with
10/// [`crate::VarType`] and [`crate::Data`] re-exported at the crate
11/// root so callers need not depend on `dune_raw`.
12#[derive(Clone, Debug)]
13pub struct Solution {
14 /// The `Plotname:` (e.g. `Operating Point`).
15 pub plotname: String,
16 /// Variable names and kinds ([`crate::VarType`]), in rawfile
17 /// order.
18 pub variables: Vec<(String, VarType)>,
19 /// One column per variable, all the same length; complex for
20 /// `.ac`, real for everything else ([`crate::Data`]).
21 pub data: Data,
22 /// Index of the abscissa (`time`, `frequency`, `v(v-sweep)`) in
23 /// `variables`; `None` for the operating point.
24 pub scale: Option<usize>,
25}
26
27impl Solution {
28 pub fn num_points(&self) -> usize {
29 self.data.num_points()
30 }
31
32 /// Real column by variable name (case-insensitive, like the 3f5
33 /// front end); `None` when missing or complex.
34 pub fn column(&self, name: &str) -> Option<&[f64]> {
35 let i = self.index(name)?;
36 match &self.data {
37 Data::Real(cols) => Some(&cols[i]),
38 Data::Complex(_) => None,
39 }
40 }
41
42 /// Complex column by variable name.
43 pub fn column_complex(&self, name: &str) -> Option<&[Complex64]> {
44 let i = self.index(name)?;
45 match &self.data {
46 Data::Complex(cols) => Some(&cols[i]),
47 Data::Real(_) => None,
48 }
49 }
50
51 pub(crate) fn index(&self, name: &str) -> Option<usize> {
52 self.variables
53 .iter()
54 .position(|(n, _)| n.eq_ignore_ascii_case(name))
55 }
56
57 /// Package as a rawfile plot (padded).
58 pub fn to_plot(&self, title: &str, date: &str) -> Plot {
59 Plot {
60 title: title.to_string(),
61 date: date.to_string(),
62 name: self.plotname.clone(),
63 padded: true,
64 commands: Vec::new(),
65 options: Vec::new(),
66 dimensions: None,
67 variables: self
68 .variables
69 .iter()
70 .map(|(n, t)| Variable::new(n.clone(), t.clone()))
71 .collect(),
72 data: self.data.clone(),
73 }
74 }
75}