pub struct Conductor { /* private fields */ }Expand description
A block of conducting material with two electrodes, solved for its potential.
Cells are cubes. The electrodes are the whole x = 0 and x = L faces, held at fixed
potentials; every other surface is insulating, so no current leaves through it. That is the
four-terminal arrangement a resistance is defined by, and it is what makes ρL/A the exact
answer for a uniform block rather than an approximation to it.
Implementations§
Source§impl Conductor
impl Conductor
Sourcepub fn new(
name: impl Into<String>,
counts: (usize, usize, usize),
dx: Length,
material: Resistivity,
drive: Voltage,
) -> Conductor
pub fn new( name: impl Into<String>, counts: (usize, usize, usize), dx: Length, material: Resistivity, drive: Voltage, ) -> Conductor
A uniform block of counts cubic cells of side dx, driven by a potential difference
across its x faces.
Sourcepub fn with_solver(self, tolerance: f64, max_iterations: usize) -> Conductor
pub fn with_solver(self, tolerance: f64, max_iterations: usize) -> Conductor
What Domain::step asks of the solver, and what it refuses below.
Exposed because a caller with a hard time budget may prefer a bounded solve to an unbounded one — and because the refusal path needs to be reachable from a test. A domain whose only failure mode cannot be provoked is a domain whose failure mode is untested.
Sourcepub fn set_resistivity(
&mut self,
i: usize,
j: usize,
k: usize,
material: Resistivity,
)
pub fn set_resistivity( &mut self, i: usize, j: usize, k: usize, material: Resistivity, )
Give one cell a different material.
The point of the whole domain: a block that is not one material has no ρL/A, and this is
how it stops being one. Out of range is ignored.
Sourcepub fn set_region(
&mut self,
which: impl FnMut(usize, usize, usize) -> bool,
material: Resistivity,
)
pub fn set_region( &mut self, which: impl FnMut(usize, usize, usize) -> bool, material: Resistivity, )
Give a whole slab of cells one material, by a predicate on cell indices.
The readable way to build a series or parallel arrangement, and the way the closed-form tests do it.
Sourcepub fn index(&self, i: usize, j: usize, k: usize) -> Option<usize>
pub fn index(&self, i: usize, j: usize, k: usize) -> Option<usize>
The flat index of a cell, or None out of range.
Sourcepub fn potential_at(&self, i: usize, j: usize, k: usize) -> Voltage
pub fn potential_at(&self, i: usize, j: usize, k: usize) -> Voltage
The potential at one cell centre.
Sourcepub fn current_density_at(&self, i: usize, j: usize, k: usize) -> DVec3
pub fn current_density_at(&self, i: usize, j: usize, k: usize) -> DVec3
The current density at one cell, by central differences on the potential.
J = −σ∇φ. At a cell against an insulating face the normal component is zero by
construction, because there is no neighbour to differ from.
Sourcepub fn current(&self) -> Current
pub fn current(&self) -> Current
The total current through the block, measured at the driven electrode.
Measured rather than derived: the current is the sum of what actually crosses the
electrode faces in the solved field. A solve that had not converged would report a current
that disagreed with the one measured at the other electrode, which is exactly the check
Conductor::current_balance makes.
Sourcepub fn current_balance(&self) -> f64
pub fn current_balance(&self) -> f64
How much the current in disagrees with the current out, relative to the current itself.
Zero for a converged solve, because charge does not accumulate. This is the number that says whether the answer is an answer — and it is measured from the two electrodes independently rather than being a residual the solver reports about itself.
Sourcepub fn resistance(&self) -> Resistance
pub fn resistance(&self) -> Resistance
The resistance the geometry has, V/I.
Not stated anywhere. For a uniform block this comes out as ρL/A to machine
precision; for anything else it comes out as whatever the shape gives, which is the reason
the domain exists.
Sourcepub fn dissipation(&self) -> Power
pub fn dissipation(&self) -> Power
The power dissipated, ∫σ|∇φ|²dV, summed over the faces where the gradient actually is.
Computed from the field rather than as V·I, so that the two agreeing is a check and not
a tautology. They agree to machine precision for a converged solve — that is Tellegen’s
theorem, and it is the sharpest single statement about whether the discretisation is
self-consistent.
Sourcepub fn dissipated_energy(&self) -> Energy
pub fn dissipated_energy(&self) -> Energy
Energy dissipated over the run.
Sourcepub fn solve(&mut self, tolerance: f64) -> bool
pub fn solve(&mut self, tolerance: f64) -> bool
Solve for the potential, to a relative residual of tolerance.
Conjugate gradients, which is exact for this system in n steps in exact arithmetic and
is symmetric positive definite because the conductances are positive and the coupling is
symmetric. Deterministic: fixed order, fixed start, no threads.
Returns whether it converged. A caller that ignores the answer gets a field that looks
like a field, which is why Domain::step refuses instead.
Sourcepub fn solve_within(&mut self, tolerance: f64, max_iterations: usize) -> bool
pub fn solve_within(&mut self, tolerance: f64, max_iterations: usize) -> bool
Solve, spending at most max_iterations.
Returns whether the tolerance was met. A false here is the whole reason the method
returns anything: the potential field left behind is smooth, bounded and shaped exactly
like an answer, and nothing downstream can tell it from one.
Source§impl Conductor
The current density as a vector, for a caller that wants J rather than φ.
impl Conductor
The current density as a vector, for a caller that wants J rather than φ.
Sourcepub fn current_density_magnitude(
&self,
i: usize,
j: usize,
k: usize,
) -> CurrentDensity
pub fn current_density_magnitude( &self, i: usize, j: usize, k: usize, ) -> CurrentDensity
|J| at a cell, which is what a picture of current crowding wants.
Sourcepub fn conductivity_at(&self, i: usize, j: usize, k: usize) -> Conductivity
pub fn conductivity_at(&self, i: usize, j: usize, k: usize) -> Conductivity
The conductivity of one cell.
Trait Implementations§
Source§impl Domain for Conductor
impl Domain for Conductor
Source§fn kind(&self) -> Kind
fn kind(&self) -> Kind
Quasi-static: charge relaxes in ε/σ, which for copper is 1.5×10⁻¹⁹ s. On any timescale a
simulation cares about, the current distribution is a solution and not a state.
Source§fn ledger(&self) -> Ledger
fn ledger(&self) -> Ledger
What it has left to give, which for a source held at a fixed voltage is a negative number that keeps getting more negative.
The same bookkeeping Winding uses: a domain paying joules out has to
say so, or the audit sees energy appear from nowhere. It is not a reserve — an ideal
voltage source has none — so what is reported is the debt.
Source§fn readings(&self) -> Vec<Reading>
fn readings(&self) -> Vec<Reading>
The resistance, the current, the dissipation and how well the solve converged.
The residual is a reading, not merely an internal number, and that is the point of having it here: an iterative solve that quietly stopped early produces a field shaped like an answer, and the only thing that would ever say otherwise is a column somebody can look at.
Source§fn as_field(&self) -> Option<&dyn ScalarField>
fn as_field(&self) -> Option<&dyn ScalarField>
The potential, in volts, as a field.
Not the current density, which is a vector and has no ScalarField. A view wanting to see
where the current crowds should take |J| from
current_density_at; the potential is what the solve
produces and what a contour plot of an electrical problem conventionally shows.
Source§fn books_balance(&self) -> bool
fn books_balance(&self) -> bool
Source§fn name(&self) -> &str
fn name(&self) -> &str
Source§fn step(
&mut self,
_t: Time,
dt: Time,
bus: &mut Exchange,
) -> Result<(), Violation>
fn step( &mut self, _t: Time, dt: Time, bus: &mut Exchange, ) -> Result<(), Violation>
dt from t, reading inputs from bus and publishing outputs
to it. A quasi-static domain ignores dt. Read moreSource§fn as_any(&self) -> Option<&dyn Any>
fn as_any(&self) -> Option<&dyn Any>
Any, so a caller can get the concrete type back out of a
Simulation — see Simulation::domain_as. Read moreSource§fn as_any_mut(&mut self) -> Option<&mut dyn Any>
fn as_any_mut(&mut self) -> Option<&mut dyn Any>
Source§fn max_stable_dt(
&self,
now: Qty<0, 0, 1, 0, 0, 0, 0>,
) -> Qty<0, 0, 1, 0, 0, 0, 0>
fn max_stable_dt( &self, now: Qty<0, 0, 1, 0, 0, 0, 0>, ) -> Qty<0, 0, 1, 0, 0, 0, 0>
now and stay stable — a CFL
condition, a diffusion limit, a contact penetration budget. Read moreSource§fn residual(&self) -> f64
fn residual(&self) -> f64
Schedule::Iterative. Zero means converged.Source§fn checkpoint(&mut self)
fn checkpoint(&mut self)
Schedule::Iterative, and Simulation::advance says so rather than
silently iterating from the wrong state.Source§fn restore(&mut self)
fn restore(&mut self)
Domain::checkpoint.Source§fn supports_restore(&self) -> bool
fn supports_restore(&self) -> bool
Source§impl ScalarField for Conductor
impl ScalarField for Conductor
Source§fn at(&self, p: LengthVec, _t: Time) -> f64
fn at(&self, p: LengthVec, _t: Time) -> f64
Trilinear between cell centres, clamped at the faces.
Source§fn gradient(&self, p: LengthVec, t: Time, h: Length) -> DVec3
fn gradient(&self, p: LengthVec, t: Time, h: Length) -> DVec3
∇φ, whose negative times σ is the current density.
Source§fn rate(&self, _p: LengthVec, _t: Time, _dt: Time) -> f64
fn rate(&self, _p: LengthVec, _t: Time, _dt: Time) -> f64
Zero. A quasi-static potential does not evolve; it is re-solved when something changes.