muse2/
simulation.rs

1//! Functionality for running the MUSE 2.0 simulation.
2use crate::asset::AssetPool;
3use crate::model::Model;
4use crate::output::DataWriter;
5use anyhow::{bail, Result};
6use log::info;
7use std::path::Path;
8
9pub mod optimisation;
10use optimisation::perform_dispatch_optimisation;
11pub mod investment;
12use investment::perform_agent_investment;
13pub mod prices;
14pub use prices::CommodityPrices;
15
16/// Run the simulation.
17///
18/// # Arguments:
19///
20/// * `model` - The model to run
21/// * `assets` - The asset pool
22pub fn run(model: Model, mut assets: AssetPool, output_path: &Path) -> Result<()> {
23    let mut writer = DataWriter::create(output_path)?;
24
25    let mut opt_results = None; // all results of dispatch optimisation
26    for year in model.iter_years() {
27        info!("Milestone year: {year}");
28
29        // Assets that have been decommissioned cannot be selected by agents
30        assets.decomission_old(year);
31
32        // NB: Agent investment is not carried out in first milestone year
33        if let Some((solution, prices)) = opt_results {
34            perform_agent_investment(&model, &solution, &prices, &mut assets);
35
36            // **TODO:** Remove this when we implement at least some of the agent investment code
37            //   See: https://github.com/EnergySystemsModellingLab/MUSE_2.0/issues/304
38            bail!("Agent investment is not yet implemented. Exiting...");
39        }
40
41        // Newly commissioned assets will be included in optimisation for at least one milestone
42        // year before agents have the option of decommissioning them
43        assets.commission_new(year);
44
45        // Write current assets to CSV. This indicates the set of assets fed into the dispatch
46        // optimisation, so we *must* do it after agent investment and new assets are commissioned
47        writer.write_assets(year, assets.iter())?;
48
49        // Dispatch optimisation
50        let solution = perform_dispatch_optimisation(&model, &assets, year)?;
51        let prices = CommodityPrices::from_model_and_solution(&model, &solution, &assets);
52
53        // Write result of dispatch optimisation to file
54        writer.write_flows(year, &assets, solution.iter_commodity_flows_for_assets())?;
55        writer.write_prices(year, &prices)?;
56
57        opt_results = Some((solution, prices));
58    }
59
60    writer.flush()?;
61
62    Ok(())
63}