Skip to main content

mech_sim/
lib.rs

1pub mod config;
2pub mod errors;
3pub mod integrator;
4pub mod metrics;
5pub mod model;
6pub mod monitor;
7pub mod outputs;
8pub mod plots;
9pub mod scenarios;
10pub mod state;
11pub mod sweep;
12
13use std::fs;
14use std::path::{Path, PathBuf};
15
16use anyhow::Result;
17
18use crate::config::{
19    OutputLayout, ResolvedRunConfig, RunConfig, ScenarioOverrides, ScenarioPreset, SweepPreset,
20};
21use crate::integrator::simulate;
22use crate::outputs::{prepare_run_root, write_run_outputs, write_sweep_outputs};
23use crate::scenarios::{build_scenario_config, build_sweep_cases};
24use crate::sweep::run_sweep;
25
26pub fn run_scenario_preset(
27    preset: ScenarioPreset,
28    overrides: ScenarioOverrides,
29    output_root: impl AsRef<Path>,
30    seed: u64,
31) -> Result<PathBuf> {
32    let output_root = output_root.as_ref();
33    let run_root = prepare_run_root(output_root)?;
34    let config = build_scenario_config(preset, overrides, seed)?;
35    let result = simulate(config)?;
36    write_run_outputs(&run_root, &result)?;
37    Ok(run_root)
38}
39
40pub fn run_sweep_preset(
41    preset: SweepPreset,
42    overrides: ScenarioOverrides,
43    output_root: impl AsRef<Path>,
44    seed: u64,
45) -> Result<PathBuf> {
46    let output_root = output_root.as_ref();
47    let run_root = prepare_run_root(output_root)?;
48    let cases = build_sweep_cases(preset, overrides, seed)?;
49    let aggregate = run_sweep(preset, cases, &run_root)?;
50    write_sweep_outputs(&run_root, &aggregate)?;
51    Ok(run_root)
52}
53
54pub fn run_config_file(path: impl AsRef<Path>) -> Result<PathBuf> {
55    run_config_file_with_overrides(path, None, None)
56}
57
58pub fn run_config_file_with_overrides(
59    path: impl AsRef<Path>,
60    output_root_override: Option<&Path>,
61    seed_override: Option<u64>,
62) -> Result<PathBuf> {
63    let path = path.as_ref();
64    let raw = fs::read_to_string(path)?;
65    let mut run_config: RunConfig = serde_json::from_str(&raw)?;
66    apply_cli_overrides(&mut run_config, output_root_override, seed_override);
67    match ResolvedRunConfig::from_run_config(run_config, path.parent())? {
68        ResolvedRunConfig::Scenario {
69            config,
70            output_layout,
71        } => {
72            let run_root = prepare_run_root(output_layout.output_root())?;
73            let result = simulate(config)?;
74            write_run_outputs(&run_root, &result)?;
75            Ok(run_root)
76        }
77        ResolvedRunConfig::Sweep {
78            preset,
79            cases,
80            output_layout,
81        } => {
82            let run_root = prepare_run_root(output_layout.output_root())?;
83            let aggregate = run_sweep(preset, cases, &run_root)?;
84            write_sweep_outputs(&run_root, &aggregate)?;
85            Ok(run_root)
86        }
87    }
88}
89
90pub fn default_output_layout() -> OutputLayout {
91    OutputLayout::default()
92}
93
94fn apply_cli_overrides(
95    run_config: &mut RunConfig,
96    output_root_override: Option<&Path>,
97    seed_override: Option<u64>,
98) {
99    match run_config {
100        RunConfig::Scenario {
101            seed, output_root, ..
102        }
103        | RunConfig::Sweep {
104            seed, output_root, ..
105        } => {
106            if let Some(value) = output_root_override {
107                *output_root = Some(value.to_path_buf());
108            }
109            if let Some(value) = seed_override {
110                *seed = Some(value);
111            }
112        }
113    }
114}