use std::collections::HashMap;
use super::resistor::SpinResistor;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Terminal(pub usize);
#[derive(Debug, Clone)]
pub struct Connection {
pub from: Terminal,
pub to: Terminal,
pub resistor: SpinResistor,
}
#[derive(Debug, Clone)]
pub struct SpinCircuit {
pub connections: Vec<Connection>,
pub voltages: HashMap<Terminal, f64>,
pub spin_accumulation: HashMap<Terminal, f64>,
}
impl SpinCircuit {
pub fn new() -> Self {
Self {
connections: Vec::new(),
voltages: HashMap::new(),
spin_accumulation: HashMap::new(),
}
}
pub fn add_connection(&mut self, from: Terminal, to: Terminal, resistor: SpinResistor) {
self.connections.push(Connection { from, to, resistor });
}
pub fn set_voltage(&mut self, terminal: Terminal, voltage: f64) {
self.voltages.insert(terminal, voltage);
}
pub fn set_spin_accumulation(&mut self, terminal: Terminal, mu_s: f64) {
self.spin_accumulation.insert(terminal, mu_s);
}
pub fn charge_current(&self, connection: &Connection) -> f64 {
let v1 = self.voltages.get(&connection.from).copied().unwrap_or(0.0);
let v2 = self.voltages.get(&connection.to).copied().unwrap_or(0.0);
let r_total = connection.resistor.total_resistance();
(v1 - v2) / r_total
}
pub fn spin_current(&self, connection: &Connection) -> f64 {
let i_charge = self.charge_current(connection);
let p = connection.resistor.current_polarization();
let mu_s1 = self
.spin_accumulation
.get(&connection.from)
.copied()
.unwrap_or(0.0);
let mu_s2 = self
.spin_accumulation
.get(&connection.to)
.copied()
.unwrap_or(0.0);
let i_s_pol = p * i_charge;
let r_s = (connection.resistor.r_up - connection.resistor.r_down).abs() / 2.0;
let i_s_diff = if r_s > 0.0 {
(mu_s1 - mu_s2) / (2.0 * r_s)
} else {
0.0
};
i_s_pol + i_s_diff
}
pub fn terminals(&self) -> Vec<Terminal> {
let mut terminals = std::collections::HashSet::new();
for conn in &self.connections {
terminals.insert(conn.from);
terminals.insert(conn.to);
}
terminals.into_iter().collect()
}
pub fn current_into(&self, terminal: Terminal) -> f64 {
let mut total = 0.0;
for conn in &self.connections {
if conn.to == terminal {
total += self.charge_current(conn);
} else if conn.from == terminal {
total -= self.charge_current(conn);
}
}
total
}
pub fn spin_current_into(&self, terminal: Terminal) -> f64 {
let mut total = 0.0;
for conn in &self.connections {
if conn.to == terminal {
total += self.spin_current(conn);
} else if conn.from == terminal {
total -= self.spin_current(conn);
}
}
total
}
}
impl Default for SpinCircuit {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_circuit_creation() {
let circuit = SpinCircuit::new();
assert_eq!(circuit.connections.len(), 0);
}
#[test]
fn test_add_connection() {
let mut circuit = SpinCircuit::new();
let resistor = SpinResistor::new(100.0, 200.0, 1.0e-6, 1.0e-12);
circuit.add_connection(Terminal(0), Terminal(1), resistor);
assert_eq!(circuit.connections.len(), 1);
}
#[test]
fn test_charge_current() {
let mut circuit = SpinCircuit::new();
let resistor = SpinResistor::new(100.0, 200.0, 1.0e-6, 1.0e-12);
circuit.add_connection(Terminal(0), Terminal(1), resistor);
circuit.set_voltage(Terminal(0), 1.0);
circuit.set_voltage(Terminal(1), 0.0);
let i = circuit.charge_current(&circuit.connections[0]);
assert!(i > 0.01);
assert!(i < 0.02);
}
#[test]
fn test_terminals() {
let mut circuit = SpinCircuit::new();
let resistor = SpinResistor::new(100.0, 200.0, 1.0e-6, 1.0e-12);
circuit.add_connection(Terminal(0), Terminal(1), resistor.clone());
circuit.add_connection(Terminal(1), Terminal(2), resistor);
let terminals = circuit.terminals();
assert_eq!(terminals.len(), 3);
}
}