use std::io::Write;
use std::ops::ControlFlow;
use std::path::Path;
use henad::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
henad::install_panic_hook();
let models = henad::models::example_models();
let folder = std::env::temp_dir().join("sir-rates");
if folder.exists() {
std::fs::remove_dir_all(&folder)?;
}
let replay = study(&models, &folder, &mut std::io::stdout())?;
let options = AppOptions::new(models, "SIR study", henad::build_info!()).opening(AppOpening::Run {
replay,
open_at: OpenAt::Start,
});
henad::app::run_native(options)?;
Ok(())
}
fn study(models: &ModelSet, folder: &Path, out: &mut impl Write) -> Result<Replay, Box<dyn std::error::Error>> {
let sir = models.get("sir").ok_or("the example set lacks SIR")?;
let mut simulation = sir
.setup()
.set("grid_width", 256u32)?
.set("grid_height", 256u32)?
.set("initial_infected_pct", 0.001f32)?
.set_text("infection_rate", "0.05")?
.with_seed(7)
.act_at("seed_outbreak", 50)?
.build(None)?;
simulation.run_to(100)?;
let stats = simulation.stats()?;
let susceptible = stats.scalar("Susceptible");
writeln!(out, "tick {}: {susceptible:?} susceptible", stats.tick())?;
simulation.set_param("infection_rate", 0.3f32)?;
simulation.act("seed_outbreak")?;
let mut samples = Vec::new();
let flow = simulation.run_sampled(500, 20, |sample| {
samples.push((sample.tick(), sample.scalar("Susceptible"), sample.scalar("Infected")));
match sample.scalar("Infected") {
Some(infected) if infected < 1.0 => ControlFlow::Break(sample.tick()),
_ => ControlFlow::Continue(()),
}
})?;
for (tick, susceptible, infected) in samples {
writeln!(out, "tick {tick}: {susceptible:?} susceptible, {infected:?} infected")?;
}
if let ControlFlow::Break(tick) = flow {
writeln!(out, "the epidemic ended by tick {tick}")?;
}
let loaded = LoadedSpec::parse(
r#"
model = "sir"
[set]
grid_width = 128
grid_height = 128
[run]
steps = 300
replicates = 4
[[block]]
design = "factorial"
factors = [{ param = "infection_rate", values = [0.2, 0.3, 0.4] }]
"#,
)?;
let mut options = SweepOptions::new(Provenance::new(henad::build_info!(), std::env::args().collect()));
options.spec_source = loaded.spec_source.clone();
options.apply_execution(&loaded.execution);
let record = run_spec(
sir,
None,
&loaded.spec,
SweepOutput::Directory(folder.to_owned()),
&options,
&mut NoProgress,
)?;
let counts = &record.report.counts;
writeln!(out, "{} of {} runs ok", counts.ok, counts.rows)?;
let results = ResultSet::open_dir(folder, 64 << 20)?;
let replay = results.replay(sir.schema(), 5)?;
let mut rebuilt = RunSetup::from_replay(sir, &replay)?.build(None)?;
rebuilt.run_to(replay.ticks)?;
let infected = rebuilt.stats()?.scalar("Infected");
writeln!(out, "run 5 ends with {infected:?} infected")?;
Ok(replay)
}