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::Result;
6use log::{error, 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
22/// * `output_path` - The folder to which output files will be written
23/// * `debug_model` - Whether to write additional information (e.g. duals) to output files
24pub fn run(
25    model: Model,
26    mut assets: AssetPool,
27    output_path: &Path,
28    debug_model: bool,
29) -> Result<()> {
30    let mut writer = DataWriter::create(output_path, &model.model_path, debug_model)?;
31
32    // Iterate over milestone years
33    let mut year_iter = model.iter_years();
34    let mut year = year_iter.next().unwrap(); // NB: There will be at least one year
35
36    // There shouldn't be assets already commissioned, but let's do this just in case
37    assets.decommission_old(year);
38
39    // **TODO:** Remove annotation when the loop actually loops
40    #[allow(clippy::never_loop)]
41    loop {
42        info!("Milestone year: {year}");
43
44        // Newly commissioned assets will be included in optimisation for at least one milestone
45        // year before agents have the option of decommissioning them
46        assets.commission_new(year);
47
48        // Write current assets to CSV. This indicates the set of assets fed into the dispatch
49        // optimisation, so we *must* do it after agent investment and new assets are commissioned
50        writer.write_assets(year, assets.iter())?;
51
52        // Dispatch optimisation
53        let solution = perform_dispatch_optimisation(&model, &assets, &[], year)?;
54        let flow_map = solution.create_flow_map();
55        let prices = CommodityPrices::calculate(&model, &solution, year);
56
57        // Write result of dispatch optimisation to file
58        writer.write_debug_info(year, &solution)?;
59        writer.write_flows(year, &flow_map)?;
60        writer.write_prices(year, &prices)?;
61
62        if let Some(next_year) = year_iter.next() {
63            year = next_year;
64
65            // NB: Agent investment is not carried out in first milestone year
66            perform_agent_investment(&model, &flow_map, &prices, &mut assets);
67
68            // Decommission assets whose lifetime has passed
69            assets.decommission_old(year);
70        } else {
71            // No more milestone years. Simulation is finished.
72            break;
73        }
74
75        // **TODO:** Remove this when we implement at least some of the agent investment code
76        //   See: https://github.com/EnergySystemsModellingLab/MUSE_2.0/issues/304
77        error!("Agent investment is not yet implemented. Exiting...");
78        break;
79    }
80
81    writer.flush()?;
82
83    Ok(())
84}