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}