use dualis::prelude::*;
fn units_are_types() {
let area: Area = Length::mm(10.0) * Length::mm(10.0);
let absorbed: Power = Irradiance::mw_per_cm2(50.0) * area * 0.02;
let capacity: HeatCapacity = Mass::g(2.0) * SpecificHeat::j_per_kg_k(858.0);
let rise: Temperature = (absorbed * Time::s(1.0)) / capacity;
println!("1. units");
println!(" 50 mW/cm^2 on a 1 cm^2 surface absorbing 2% warms 2 g of glass");
println!(" by {:.3} mK in a second", rise.to_si() * 1e3);
}
struct Heater {
reserve: f64,
}
impl Domain for Heater {
fn name(&self) -> &'static str {
"heater"
}
fn step(&mut self, _t: Time, dt: Time, bus: &mut Exchange) -> Result<(), Violation> {
let joules = (100.0 * dt.to_si()).min(self.reserve); self.reserve -= joules;
bus.publish(HEAT, joules);
Ok(())
}
fn ledger(&self) -> Ledger {
Ledger::new().with(quantity::ENERGY, self.reserve)
}
}
struct Slab {
stored: f64,
lossy: bool,
}
impl Domain for Slab {
fn name(&self) -> &'static str {
"slab"
}
fn step(&mut self, _t: Time, _dt: Time, bus: &mut Exchange) -> Result<(), Violation> {
let arrived = bus.take(HEAT);
self.stored += if self.lossy { 0.9 * arrived } else { arrived };
Ok(())
}
fn ledger(&self) -> Ledger {
Ledger::new().with(quantity::ENERGY, self.stored)
}
}
fn run(lossy: bool) -> Result<f64, Violation> {
let mut sim = Simulation::new(Schedule::Staggered)
.with(Heater { reserve: 500.0 })
.with(Slab { stored: 0.0, lossy });
for _ in 0..100 {
sim.advance(Time::ms(50.0))?;
}
Ok(sim
.ledger()
.get(quantity::ENERGY)
.expect("both domains report energy"))
}
fn main() {
units_are_types();
println!("\n2. a correct pair of domains");
let total = run(false).expect("the books close");
assert!((total - 500.0).abs() < 1e-9, "total {total}");
println!(" 500.0 J started in the heater's tank");
println!(" {total:.1} J is still accounted for after five seconds");
println!("\n3. the same pair, with the slab booking 90% of what it takes");
match run(true) {
Ok(total) => panic!("the audit should have refused this: {total}"),
Err(v) => {
println!(" advance() returned Err, and this is the whole message:");
println!("\n {v}\n");
assert_eq!(v.quantity, quantity::ENERGY);
println!(" v.quantity = {:?}", v.quantity);
println!(" v.site = {:?}", v.site);
println!(" v.before = {:.4} J", v.before);
println!(" v.after = {:.4} J", v.after);
}
}
println!("\nRead next: AGENTS.md for the API surface, examples/ for physics that is");
println!("checked in public, CONTRIBUTING.md if you are adding to it.");
}