Skip to main content

Domain

Trait Domain 

Source
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§

Source

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.

Source

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§

Source

fn kind(&self) -> Kind

Whether it has state to roll forward. Defaults to Kind::Evolving.

Source

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.

Source

fn residual(&self) -> f64

How far this domain still is from agreeing with its neighbours, for Schedule::Iterative. Zero means converged.

Source

fn ledger(&self) -> Ledger

What this domain is holding, for the conservation audit.

Source

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.

Source

fn restore(&mut self)

Restore the last Domain::checkpoint.

Source

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.

Source

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.

Source

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.

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

What this domain is called. Used to look it up and to name it in a violation. Read more
Source§

fn kind(&self) -> Kind

Whether it has state to roll forward. Defaults to Kind::Evolving.
Source§

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. Read more
Source§

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. Read more
Source§

fn residual(&self) -> f64

How far this domain still is from agreeing with its neighbours, for Schedule::Iterative. Zero means converged.
Source§

fn ledger(&self) -> Ledger

What this domain is holding, for the conservation audit.
Source§

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.
Source§

fn restore(&mut self)

Restore the last Domain::checkpoint.
Source§

fn supports_restore(&self) -> bool

Whether Domain::checkpoint and Domain::restore actually do something. Read more
Source§

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. Read more
Source§

fn as_field(&self) -> Option<&dyn ScalarField>

This domain as a ScalarField, if it has one to show. Read more

Dyn 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.

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

Source§

fn kind(&self) -> Kind

Source§

fn max_stable_dt(&self, now: Time) -> Time

Source§

fn step( &mut self, t: Time, dt: Time, bus: &mut Exchange, ) -> Result<(), Violation>

Source§

fn residual(&self) -> f64

Source§

fn ledger(&self) -> Ledger

Source§

fn checkpoint(&mut self)

Source§

fn restore(&mut self)

Source§

fn supports_restore(&self) -> bool

Source§

fn as_any(&self) -> Option<&dyn Any>

Source§

fn as_field(&self) -> Option<&dyn ScalarField>

Implementors§