const SIZE: usize = 32;
fn coords_to_index(x: usize, y: usize) -> usize {
x * SIZE + y
}
fn index_to_coords(idx: usize) -> (usize, usize) {
(idx % SIZE, idx / SIZE)
}
const RESISTANCE: f64 = 1.0;
const CAPACITANCE: f64 = 1.0;
const TIME_STEP: f64 = RESISTANCE * CAPACITANCE / 10.0;
const ACCURACY: f64 = 1e-8;
fn derivative_function(
voltage: &impulse_response::SparseVector,
derivative: &mut impulse_response::SparseVector,
) {
let mut adjacent = Vec::with_capacity(4);
for (&point_index, &point_voltage) in voltage.iter() {
adjacent.clear();
let (x, y) = index_to_coords(point_index);
if x > 0 {
adjacent.push(coords_to_index(x - 1, y));
}
if x + 1 < SIZE {
adjacent.push(coords_to_index(x + 1, y));
}
if y > 0 {
adjacent.push(coords_to_index(x, y - 1));
}
if y + 1 < SIZE {
adjacent.push(coords_to_index(x, y + 1));
}
let mut total_current = 0.0;
for adj in adjacent.iter() {
match voltage.get(adj) {
Some(&adj_voltage) => {
total_current += (point_voltage - adj_voltage) / RESISTANCE;
}
None => {
let current = point_voltage / RESISTANCE;
if current / CAPACITANCE * TIME_STEP >= f64::EPSILON {
total_current += current;
derivative.insert(
*adj,
current / CAPACITANCE + derivative.get(adj).unwrap_or(&0.0),
);
}
}
}
}
derivative.insert(point_index, -total_current / CAPACITANCE);
}
}
fn main() {
let mut model =
impulse_response::Model::new(TIME_STEP, ACCURACY, TIME_STEP / 10_000.0, f64::EPSILON);
for node in 0..SIZE * SIZE {
model.touch(node)
}
println!("Model Size: {} Nodes", model.len());
let mut state = vec![0.0; SIZE * SIZE];
let mut next_state = vec![0.0; SIZE * SIZE];
const PROBE1: (usize, usize) = (SIZE / 2, SIZE / 2);
const PROBE2: (usize, usize) = (PROBE1.0 + 2, PROBE1.1 + 1);
const V_SOURCE: f64 = 1.0;
const V_GROUND: f64 = 0.0;
state[coords_to_index(PROBE1.0, PROBE1.1)] = V_SOURCE;
state[coords_to_index(PROBE2.0, PROBE2.1)] = V_GROUND;
let mut resistance = f64::NAN; loop {
model.advance(&state, &mut next_state, derivative_function);
std::mem::swap(&mut state, &mut next_state);
let delta_voltage = V_SOURCE - state[coords_to_index(PROBE1.0, PROBE1.1)];
let current = delta_voltage * CAPACITANCE / TIME_STEP;
let new_resistance = V_SOURCE / current;
state[coords_to_index(PROBE1.0, PROBE1.1)] = V_SOURCE;
state[coords_to_index(PROBE2.0, PROBE2.1)] = V_GROUND;
let delta_resistance = new_resistance - resistance;
resistance = new_resistance;
if delta_resistance.abs() <= ACCURACY {
break;
}
}
println!("Equivalent Resistance: {} Ohms", resistance);
println!(
"Exact Answer: 4/PI - 1/2 = {} Ohms",
4.0 / std::f64::consts::PI - 0.5
);
}