Skip to main content

dune_core/
op.rs

1//! `.op` — the DC operating point (`ckt/dcop.c`: `CKTop` with
2//! `MODEDCOP|MODEINITJCT`, then one output point).
3
4use dune_raw::VarType;
5
6use crate::circuit::{Circuit, VarKind};
7use crate::engine::Engine;
8use crate::error::Error;
9use crate::options::Options;
10use crate::solution::Solution;
11
12/// Result of an operating-point analysis.
13#[derive(Clone, Debug)]
14pub struct Op {
15    pub solution: Solution,
16    /// Setup/convergence remarks the 3f5 would print as warnings
17    /// (diode breakdown matching, nodeset issues, …).
18    pub notes: Vec<String>,
19}
20
21impl Circuit {
22    /// Compute the operating point.
23    pub fn op(&self, opts: &Options) -> Result<Op, Error> {
24        let built = self.build(opts)?;
25        let notes = built.notes.clone();
26        let mut engine = Engine::new(built);
27        engine.op(opts)?;
28
29        // Mirror what ngspice saves for `.op`: every non-ground,
30        // non-internal node as `v(name)` and every branch current as
31        // `i(name)` (device-internal nodes are solved but not output,
32        // see `saved_node`).
33        let mut variables = Vec::new();
34        let mut columns = Vec::new();
35        for i in 1..engine.vars.len() {
36            let name = &engine.vars.names[i];
37            match engine.vars.kinds[i] {
38                VarKind::Node if crate::circuit::saved_node(name) => {
39                    variables.push((format!("v({name})"), VarType::Voltage));
40                    columns.push(vec![engine.sol[i]]);
41                }
42                VarKind::Branch => {
43                    variables.push((format!("i({name})"), VarType::Current));
44                    columns.push(vec![engine.sol[i]]);
45                }
46                _ => {}
47            }
48        }
49        Ok(Op {
50            solution: Solution {
51                plotname: "Operating Point".to_string(),
52                variables,
53                data: dune_raw::Data::Real(columns),
54                scale: None,
55            },
56            notes,
57        })
58    }
59}