Skip to main content

Crate dualis

Crate dualis 

Source
Expand description

dualis: physics for simulated worlds, in one dependency.

A facade over the workspace. Nothing is implemented here — the point is that a consumer writes dualis = "0.2" rather than naming seven crates, and that the integration tests which need two domains at once have somewhere to live.

use dualis::prelude::*;

// A lamp, a filter, and the question that needs both.
let lamp = SpectralPower::new(
    Spectrum::blackbody(3200.0),
    Power::w(1.0),
    VISIBLE_RANGE,
);
let green = Spectrum::bands(vec![[500.0, 560.0]], 0.95, 0.0);
let through = lamp.through(&green);
assert!(through < lamp.total());

§Start here

Three ideas carry the whole library.

  1. Units are types. Dimensions live in the type, so Length + Time does not compile. One place may hold a factor of a thousand — a unit-bearing constructor — and to_si() is the only way back to a bare f64.
  2. A domain is anything that steps. Domain requires name and step; everything else has a default. Override ledger so the audit has something to check.
  3. Domains never call each other. They meet on Exchange, a bus of named channels carrying SI amounts — joules, not watts. A ledger says what you are holding, not what has passed through you.

And the reason to pick this over a general-purpose engine: conservation is audited every step, so a wrong model does not run quietly. advance returns a Violation naming the quantity, the site, and the before and after — a correctness signal you can act on without a human noticing first.

energy destroyed at simulation: 5.000000e2 became 4.995000e2,
a relative change of 1.000e-3 against a tolerance of 1.000e-9

Be clear about the limit: the audit catches quantities appearing or vanishing, amounts left unclaimed on the bus, and fluxes disagreeing face by face across a shared boundary. It does not catch a model that is internally consistent and physically wrong — publish a power where a joule was wanted and both sides agree perfectly about a number off by 1/dt. For that, check against something the code did not compute: a closed form, an exact limit, or a convergence rate.

cargo run --example agents_quickstart is all of the above as a running program, including a deliberate leak so the failure is visible. AGENTS.md in the repository is the one-page version.

§The dependency rule

dualis-units      no dependencies but glam and serde
dualis-core       depends on units
dualis-optics     depends on core
dualis-thermal    depends on core
dualis-mechanics  depends on core
dualis-acoustic   depends on core
dualis-molecular  depends on core
dualis            depends on all of them

None of the five domains knows about any of the others. They meet on the kernel’s Exchange, and each one that arrived left the others untouched — which is the claim the split was made to test, now held five times.

Re-exports§

pub use dualis_acoustic as acoustic;
pub use dualis_core as core;
pub use dualis_electrical as electrical;
pub use dualis_mechanics as mechanics;
pub use dualis_molecular as molecular;
pub use dualis_optics as optics;
pub use dualis_thermal as thermal;
pub use dualis_units as units;

Modules§

prelude
Everything most simulations need, in one use.