pub trait Domain {
// Required methods
fn name(&self) -> &str;
fn step(
&mut self,
t: Time,
dt: Time,
bus: &mut Exchange,
) -> Result<(), Violation>;
// Provided methods
fn kind(&self) -> Kind { ... }
fn max_stable_dt(&self, now: Time) -> Time { ... }
fn residual(&self) -> f64 { ... }
fn ledger(&self) -> Ledger { ... }
fn checkpoint(&mut self) { ... }
fn restore(&mut self) { ... }
fn supports_restore(&self) -> bool { ... }
fn as_any(&self) -> Option<&dyn Any> { ... }
fn as_field(&self) -> Option<&dyn ScalarField> { ... }
}Expand description
One piece of physics.
The only required methods are the name and the step; the rest have defaults that describe a well-behaved evolving domain with no stability limit and no books to keep.
Required Methods§
Sourcefn name(&self) -> &str
fn name(&self) -> &str
What this domain is called. Used to look it up and to name it in a violation.
Borrowed rather than &'static str, so a name can come from a scene file. That was
the first thing the workspace’s own application could not do: every constructor
wanted a compile-time name and the name it had was a String read off disk, so it
leaked one per domain to get past the signature.
Sourcefn 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>
Advance by dt from t, reading inputs from bus and publishing outputs
to it. A quasi-static domain ignores dt.
Must be a pure function of its state and its inputs: no wall clock, no
unordered reduction, no shared generator. Rng::for_index
is how a domain gets randomness without giving that up.
Provided Methods§
Sourcefn kind(&self) -> Kind
fn kind(&self) -> Kind
Whether it has state to roll forward. Defaults to Kind::Evolving.
Sourcefn max_stable_dt(&self, now: Time) -> Time
fn max_stable_dt(&self, now: Time) -> Time
The largest step this domain can take from now and stay stable — a CFL
condition, a diffusion limit, a contact penetration budget.
Infinite means “no limit”, which is the honest answer for a quasi-static domain and for a linear one being solved implicitly.
Sourcefn residual(&self) -> f64
fn residual(&self) -> f64
How far this domain still is from agreeing with its neighbours, for
Schedule::Iterative. Zero means converged.
Sourcefn checkpoint(&mut self)
fn checkpoint(&mut self)
Save state so an iterative sweep can be re-run from the same starting
point. A domain that does not implement this cannot take part in
Schedule::Iterative, and Simulation::advance says so rather than
silently iterating from the wrong state.
Sourcefn restore(&mut self)
fn restore(&mut self)
Restore the last Domain::checkpoint.
Sourcefn supports_restore(&self) -> bool
fn supports_restore(&self) -> bool
Whether Domain::checkpoint and Domain::restore actually do something.
Schedule::Iterative refuses to run a domain that says no, rather than iterating
from the wrong state and reporting a residual that means nothing.
Sourcefn as_any(&self) -> Option<&dyn Any>
fn as_any(&self) -> Option<&dyn Any>
This domain as Any, so a caller can get the concrete type back out of a
Simulation — see Simulation::domain_as.
Opt-in, and returning None by default, because it cannot be automatic. Deriving it
from the trait would need Domain: Any plus upcasting dyn Domain to dyn Any,
which is a newer Rust than this crate promises. A domain that wants to be inspected
writes fn as_any(&self) -> Option<&dyn Any> { Some(self) } and is done.
The coupling never needs this: domains meet through Exchange and nothing else,
which is the property the whole design rests on. What needs it is everything around
the simulation — a test asserting a temperature profile, a visualiser drawing one —
and that is a reader, not a participant.
Sourcefn as_field(&self) -> Option<&dyn ScalarField>
fn as_field(&self) -> Option<&dyn ScalarField>
This domain as a ScalarField, if it has one to show.
Opt-in and None by default, in the same style as Domain::as_any and for a
sharper reason than that one. ScalarField was written as the interface a visualiser
would read a simulation through, and then a visualiser found it unreachable: it holds
&dyn Domain, and there was no way to ask that for a field. So it downcast to
concrete types instead and knew every domain by name — precisely what the interface
existed to avoid.
A domain with a field writes fn as_field(&self) -> Option<&dyn ScalarField> { Some(self) }. See Simulation::field.
Trait Implementations§
Source§impl Domain for Box<dyn Domain>
Delegation, so a domain chosen at run time can be added like any other.
impl Domain for Box<dyn Domain>
Delegation, so a domain chosen at run time can be added like any other.
Without this a caller holding Box<dyn Domain> — which is what building from data
produces — could not hand it to Simulation::with, even though the simulation stores
exactly that internally. Prefer Simulation::with_boxed, which avoids boxing the box;
this impl is here so that generic code over impl Domain works on a boxed one too.
Source§fn name(&self) -> &str
fn name(&self) -> &str
Source§fn kind(&self) -> Kind
fn kind(&self) -> Kind
Kind::Evolving.Source§fn max_stable_dt(&self, now: Time) -> Time
fn max_stable_dt(&self, now: Time) -> Time
now and stay stable — a CFL
condition, a diffusion limit, a contact penetration budget. Read moreSource§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 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§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_field(&self) -> Option<&dyn ScalarField>
fn as_field(&self) -> Option<&dyn ScalarField>
ScalarField, if it has one to show. Read moreDyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".
Implementations on Foreign Types§
Source§impl Domain for Box<dyn Domain>
Delegation, so a domain chosen at run time can be added like any other.
impl Domain for Box<dyn Domain>
Delegation, so a domain chosen at run time can be added like any other.
Without this a caller holding Box<dyn Domain> — which is what building from data
produces — could not hand it to Simulation::with, even though the simulation stores
exactly that internally. Prefer Simulation::with_boxed, which avoids boxing the box;
this impl is here so that generic code over impl Domain works on a boxed one too.