Skip to main content

Simulation

Struct Simulation 

Source
pub struct Simulation { /* private fields */ }
Expand description

A set of domains sharing a clock.

Implementations§

Source§

impl Simulation

Source

pub fn new(schedule: Schedule) -> Simulation

Domains are stepped in the order they are added. That order is part of the physics under a staggered schedule — put the quasi-static producers before the evolving consumers — and it is fixed rather than discovered, so two runs take the same path.

Source

pub fn with_boxed(self, domain: Box<dyn Domain>) -> Simulation

Add a domain whose type was chosen at run time.

What Simulation::with cannot do: building a domain from a scene file produces a Box<dyn Domain>, and with wants a concrete type. The simulation has always stored boxes internally, so this is the shorter path and not a wider one.

Source

pub fn with(self, domain: impl Domain + 'static) -> Simulation

Add a domain. Order matters for Schedule::Staggered and its relatives: a domain sees the output of those declared before it from this step, and of those after it from the last one.

Source

pub fn transfer_tolerance(self, tol: f64) -> Simulation

Absolute tolerance on the bus audit, in SI units of whatever is on the channel. Default 1e-12.

Source

pub fn conservation_tolerance(self, tol: f64) -> Simulation

Relative tolerance on the whole-simulation conservation audit across a step, for every quantity that has no override. Default 1e-9.

Source

pub fn conservation_tolerance_for( self, quantity: &'static str, tol: f64, ) -> Simulation

Relative tolerance for one quantity, overriding the default.

The reason this exists: a Barnes-Hut N-body gives up exact momentum by construction, and energy in a rigid room is exact to 1e-15. Under one number either the momentum check refuses a correct run or the energy check stops being able to see anything. A quantity’s achievable accuracy is a property of the scheme carrying it.

let sim = Simulation::new(Schedule::Staggered)
    .conservation_tolerance(1e-12)
    .conservation_tolerance_for(quantity::MOMENTUM, 1e-6);
assert_eq!(sim.tolerances().for_quantity(quantity::ENERGY), 1e-12);
assert_eq!(sim.tolerances().for_quantity(quantity::MOMENTUM), 1e-6);
Source

pub fn tolerances(&self) -> &Tolerances

What this simulation checks each quantity against.

Source

pub fn time(&self) -> Time

How far the simulation has been advanced.

Source

pub fn bus(&self) -> &Exchange

The coupling bus, for reading what crossed between domains.

Source

pub fn domains(&self) -> impl Iterator<Item = &dyn Domain> + '_

Every domain, in the order they were added.

domain answers by name, which is right for a caller that knows what it is looking for and useless for one that must visit them all. A layer capturing a run has to enumerate, and without this it had to be handed the list by whoever built the simulation — which means the layer above knows the composition rather than asking.

Order is declaration order, which is also execution order under the staggered schedules, so a caller iterating this sees domains in the order they act.

Source

pub fn domain(&self, name: &str) -> Option<&dyn Domain>

A domain by name, through the trait. For the concrete type, see Simulation::domain_as.

Source

pub fn field(&self, name: &str) -> Option<&dyn ScalarField>

A domain’s ScalarField, if it has one and opted in.

The domain-agnostic counterpart of Simulation::domain_as: a renderer can sample every field in a simulation without knowing what any of them are. That was the whole point of ScalarField and it was not reachable until Domain::as_field existed.

Source

pub fn domain_as<T: Any>(&self, name: &str) -> Option<&T>

A domain by name and concrete type, for a caller that needs more than the Domain trait exposes — a temperature profile, a body’s position.

Returns None if the name is not here, if the type is wrong, or if that domain did not implement Domain::as_any. Prefer Simulation::field when what is wanted is a field to sample: that one does not need the concrete type at all.

Source

pub fn domain_as_mut<T: Any>(&mut self, name: &str) -> Option<&mut T>

The same, mutably, for a caller closing a feedback loop between steps.

None if there is no such domain, if it is not a T, or if it does not implement Domain::as_any_mut — three different reasons that look alike from here, which is why that method’s documentation asks for it to be implemented beside as_any.

Source

pub fn ledger(&self) -> Ledger

Every domain’s books, summed.

Source

pub fn advance(&mut self, dt: Time) -> Result<Report, Violation>

Advance every domain by dt.

Fails without advancing the clock if a domain fails, if the bus does not balance, if an iterative coupling does not converge, or if the totalled ledgers moved by more than the conservation tolerance.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.